Nowe posty

xx Problem ze sterownikami. (5)
2024-04-13, 21:25:16
xx Instalacja xfce4 (2)
2024-04-13, 16:20:17
xx Serie kompilacji bez instalacji dla “emerge” w Gentoo (2)
2024-04-08, 18:40:04
xx Plasma 6 w Neonie ssie trochę mniej ... (17)
2024-04-05, 10:03:46
xx Problem z Linux Lite po instalacji (3)
2024-04-03, 14:23:40
xx Jak właczyć num locka przy starcie systemu debian 12? (12)
2024-04-02, 17:43:54
xx Brak dźwieku w systemie. (5)
2024-04-02, 16:13:41
xx Dystrybucja pod HP Omen (7)
2024-03-29, 11:33:05
xx [Poradnik] Wyszukiwanie Sterowników (2)
2024-03-27, 21:08:23
xx Ile pingwinów? (1)
2024-03-27, 08:59:24

Autor Wątek: Kopiowanie części pliku  (Przeczytany 5308 razy)

rogal180

  • Gość
Kopiowanie części pliku
« dnia: 2011-10-29, 19:13:15 »
Witam ,

Mam problem z programowaniem w czystym c , mianowicie chciałbym aby z pliku wczytanego przekopiowały się 10 ostatnich linijek . Kompiluje się ale nic nie kopiuje . W ogóle chciałbym użyć
 tail -n 10 ale nie wiem jak to w programowaniu wykorzystać . Z góry dziękuję . Pozdrwiam

Narazie mam taki kod :
#include 
#include
#include
#include
#include
#define MAX 300
int main(int argc, char ** argv)
{
        if(argc<3)
                return -1;
        int n,i;
        char buffer[MAX];
        int fd = open(argv[1], O_RDONLY);
        int fd2 = open(argv[2], O_WRONLY| O_CREAT|O_TRUNC, 0600);

        if(fd == -1 || fd2 == -1)
        {
                printf("Błąd\\n");
                return -1;
        }

        lseek(fd, 10, SEEK_END);

        while((n=read(fd, buffer, MAX))>0)
        {
          write(fd2, buffer, n);
        }


        close(fd);
        close(fd2);
        return 0;
}

jk33

  • Gość
Kopiowanie części pliku
« Odpowiedź #1 dnia: 2011-10-29, 20:06:51 »
Cytat: rogal180
lseek(fd, 10, SEEK_END);
Przeczytaj manuala do lseek i powiedz dokładnie co mówi ta linia.
(szczególnie w którą stronę od końca pliku przesuwa).

Uprzedzając następne pytanie: plik widzisz tu jako strumień bajtów, nie linii i linie trzeba samemu policzyć.

Co do tail: biblioteka standardowa C zawiera funkcję popen.

pozdrawiam, Janek

rogal180

  • Gość
Kopiowanie części pliku
« Odpowiedź #2 dnia: 2011-10-29, 21:24:42 »
OKi dzięki

Mam jeszcze jedno pytanko jaki potok należy wykorzystać żeby wyświetlić ostatnie dziesięć znaków w pliku  ?
Wymyśliłem coś takiego : grep plik.txt | tail -n 10 | wc -c
wiem , że wc liczy lecz może Wiecie jak to inaczej zapisać ?
Pozdrawiam

ZipoKing

  • Gość
Kopiowanie części pliku
« Odpowiedź #3 dnia: 2011-10-30, 01:22:14 »
man tail
Odszukaj informacje o opcji -c
Poza tym, tail domyślnie pokazuje 10 ostatnich wierszy, więc używanie opcji -n 10 (można też w skrócie: tail -10) jest niepotrzebne. I zamiast grep plik | tail użyj po prostu tail plik - pamiętaj o prostocie!

rogal180

  • Gość
Kopiowanie części pliku
« Odpowiedź #4 dnia: 2011-10-30, 18:00:34 »
Tylko , że : "tail -c 10" plik wypisuje : aaaaaaaaa
co ciekawe gdy są polskie znaki to : aaąaaaaa
poprawnie dopiero przy "tail -c 13" : aaaaaaaaaa
jest na to jakiś sposób ?
I mam jeszcze jedno pytanko . Jak wypisać np. 10 słów bo nie ma chyba tail -w ?

Brix

  • Gość
Kopiowanie części pliku
« Odpowiedź #5 dnia: 2011-10-30, 21:40:43 »
I absolutnie prawidłowo zauważyłeś problem, ponieważ opcja -c nie obsługuje znaków, ale bajty! A bajt nie musi oznaczać znaku, bo są np. znaki wielobajtowe, kody końca linii i inne takie.

Może rozwiązaniem problemu są wyrażenia regularne, ale w tej chwili dopiero co wróciłem i naprawdę nie mam sił myśleć :)

Coś np. jak: (to tylko moje ułomne przykłady!)

echo "przykładowytekst1234ą6" | sed 's/.*\\(....$\\)/\\1/g'
(wyświetla ostatnie 4 znaki)

echo "Ala ma kota, a kot ma   Alę" | sed 's/.* \\([^ ]\\+ \\+[^ ]\\+$\\)/\\1/g'
(wyświetla dwa ostatnie słowa)

  • Gość
Kopiowanie części pliku
« Odpowiedź #6 dnia: 2011-10-30, 22:02:04 »
tail -c wypisuje ostatnie X bajtów, a nie znaków. Najwyraźniej plik kończy się uniksowym znakiem nowego wiersza, który zajmuje jeden bajt. Polski znak zaś prawdopodobnie zajmuje dwa bajty. Gdybyś używał unikodu i miał tam jakieś znaki z alfabetów dalekowschodnich, prawdopodobnie zajmowałyby trzy bajty.

Sposób na to na pewno jakiś jest, ale ja nie znam na tyle dobrze C++, by podpowiedzieć, z czego należy skorzystać.

Ksanderon

  • Gość
Kopiowanie części pliku
« Odpowiedź #7 dnia: 2011-10-31, 00:40:57 »
wystarczą zwykłe ciny, scanefy,ready czy co tam lubisz :)

w utf-8 dla znaków z przedziału ASCII od 0 do 127 (czyli dla np j.ang) znak jest mapowany jako jeden bajt. Dla znaków powyżej (np. polskie znaki) jest mapowany jako dwa bajty (lub więcej- w "egzotycznych zestawach"- pytanie czy ciebie one obchodzą jeśli tak to na wikipedii jest to opisane: np. http://pl.wikipedia.org/wiki/UTF-8 i http://pl.wikipedia.org/wiki/Unicode dodatkowo pomocne może być http://www.evanjones.ca/unicode-in-c.html). Istnieją też do tego "hiper extended ultra biblioteki" np. ICU ale w takim jak to zadaniu bym nie przesadzał.

tutaj zmajstrowałem na szybko, bezmyślnie takie cusik i o dziwo działa (chyba):
		string a;
string b;
unsigned int blokada=10;
unsigned int licznik=0;
unsigned int i,j=0;
cin>>a;
i=a.size();
while (licznik {
b[j++]=a[i--];
if(a[i+1]<=0) b[j++]=a[i--];
licznik++;
}
j--; while(j>0) cout<
#edit: Boshe... ale jestem pustakiem. W szkole nie uczyli czytania ze zrozumieniem. ^^(powyżej) wyświetla 10 ostatnich znaków utf-8. Dla linii wystarczyłoby inkrementować "licznik" tylko gdy wystąpi znak njulajn. Dla słów gdy wystąpi jakikolwiek znak biały. To ma pokazać jedynie zasadę działania.

Offline vanhelzing

  • Users
  • Prawie jak Guru
  • ****
  • Wiadomości: 314
    • Zobacz profil
Kopiowanie części pliku
« Odpowiedź #8 dnia: 2011-10-31, 00:50:06 »
#include 
#include
#include
#include
#include

#define MAX 300

int main(int argc, char ** argv)
{
  if(argc<3) return -1;

  int n, i, b, c, r;
  int l, lines;

  char buffer[MAX+1];
  int fd = open(argv[1], O_RDONLY);
  int fd2 = open(argv[2], O_WRONLY| O_CREAT|O_TRUNC, 0600);

  if (fd == -1 || fd2 == -1) {
    printf("Błąd\\n");
    return -1;
  }

  lines = 10;  // licznik linii (odlicza od tylu)

  b = 1;      // numer bloku do skopiowania liczony od konca
  c = 0;      // rozmiar danych do skopiowania w bajtach
  r = MAX;    // offset bloku od poczatku pliku (na poczatek ustawiam
              //   r >= MAX)

  // policz liczbe bajtow do skopiowania:
  do {
    if (r >= MAX) {
      r = lseek(fd, -(MAX*b), SEEK_END);  // maksymalny rozmiar nastepnego
                                          // bloku to offset od poczatku pliku
      n = read(fd, buffer, MAX);
    }
    else {   // brak wystarczajacej ilosci danych do wczytania
      lseek(fd, 0, SEEK_SET);    // ustaw wskaznik na poczatek
      n = read(fd, buffer, r);  // i wczytaj reszte z poprzedniego przesuniecia
    }

    for (i = n-1; i >= 0 && lines > 0; i--) {  // policz znaki '\\n' w buforze
      c++;                                    // licz znaki
      if (buffer[i] == '\\n') {  // nowa linia
        lines--;
      }
    }
    b++;                            // w razie potrzeby wczytaj nowy blok danych
  } while (lines > 0 && n == MAX);  // sa jeszcze linie i nie jest to koniec pliku

  // kopiuj dane
  lseek(fd, -c, SEEK_END);
  while((n=read(fd, buffer, MAX))>0) {
    write(fd2, buffer, n);
  }

  close(fd);
  close(fd2);
  return 0;
}
Przykład działa z utf-8. Używanie taila w c dla takiego banału, to lekki przerost formy nad treścią.
Za koniec linii przyjąłem znak '\\n'.