[PC] Przeglądanie plików w C

W tym miejscu zadajemy pytania na temat języka C, dzielimy się swoją wiedzą, udzielamy wsparcia, rozwiązujemy problemy programistyczne.
Awatar użytkownika
WoodPaker
User
User
Posty: 136
Rejestracja: czwartek 17 wrz 2015, 19:23
Lokalizacja: USA
Kontaktowanie:

[PC] Przeglądanie plików w C

Postautor: WoodPaker » poniedziałek 19 paź 2015, 20:49

Ponieważ nie mogę założyć nowego wątku w dziale z językami programowania to postanowiłem napisać tutaj z nadzieją, że ktos to przeniesie gdzie należy.
Moje pytanie dotyczy operacji wejścia/wyjścia na plikach (PC) i brzmi nastepująco: Jak odczytywać plik od końca? O co mi chodzi. Otóż mam plik, który może mieć nawet kilka GB (więc wczytywanie do pamięci odpada). W pliku tym wystepuje pewna fraza nawet kilkaset razy. Mnie interesuje tylko ostatnie jej wystąpienie. Wiem jak czytac plik od początku do końca ale w tym przypadku chciałbym zrobić to w drugą stronę żeby łatwiej znaleźć te frazę. Czy ktoś zna rozwiązanie tego problemu?
Life is to short to eject USB safely

Awatar użytkownika
PROTON
Expert
Expert
Posty: 527
Rejestracja: czwartek 08 paź 2015, 18:35
Lokalizacja: Warszawa

Re: [PC] Przeglądanie plików w C

Postautor: PROTON » poniedziałek 19 paź 2015, 21:33

Po pierwsze użył bym fopen64() do dużych plików.

Kod: Zaznacz cały

FILE *f;
f = fopen64(filename, "r");
fseek(f, 0, SEEK_END);
filesize = ftell(f);
...
fseek(f, offset, SEEK_SET);


Pod filesize masz rozmiar pliku, a offset ustawiasz pozycje od której chcesz czytać.
Gott weiß ich will kein Engel sein.

Awatar użytkownika
WoodPaker
User
User
Posty: 136
Rejestracja: czwartek 17 wrz 2015, 19:23
Lokalizacja: USA
Kontaktowanie:

Re: [PC] Przeglądanie plików w C

Postautor: WoodPaker » poniedziałek 19 paź 2015, 21:39

To nie rozwiązuje mojego problemu gdyz nie wiem gdzie w pliku jest faza. Wiem tylko, że występuje kilka razy i potrzebuje jej ostatniego wystapienia
Tutaj jest plik
https://www.dropbox.com/s/ybhhmdnh9sk42 ... o.out?dl=0
W środku wystepuje fraza HF=numerek MP2=numerek. W lini numer 6169 ta fraza występuje ostatni raz.
To samo dotyczy frazy "Dipole moment". W linii 5656 występuje ostatni raz.
Potrzebuje włąśnie te linie wyłuskac i te numerki. O ile samo parsowanie tekstu jest juz banalne to odnalezienie tych "ostatnich" fraz już takie proste dla mnie nie jest. Co jest ważne to pliki te mają różną wielkośc i dane, których szukam nie sa zawsze w takiej samej odległości od końca.
Life is to short to eject USB safely

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

Re: [PC] Przeglądanie plików w C

Postautor: mokrowski » wtorek 20 paź 2015, 00:07

Przepis:
1. Czytasz plik od tyłu z użyciem ustawiania pozycji przez lseek() i pamięcią ilości bajtów czytanych od tyłu.
2. Każdy znak przeczytany wstawiasz do tablicy.
3. Jak znajdziesz znak '\n', to w tablicy będzie cała 1 linia.
4. W linii tej szukasz wystąpienia znaków wzorca (u Ciebie "HF=") i zapamiętujesz indeks.
5. Pozycja w pliku to offset z pkt. 1 zsumowany (lub odjęty jeśli liczyć będziesz od tyłu) z indeksem tablicy linii.
6. Uzyskałeś przesunięcie w pliku a dalej... parsujesz już plik jak chcesz/umiesz/potrzebujesz...
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

Awatar użytkownika
WoodPaker
User
User
Posty: 136
Rejestracja: czwartek 17 wrz 2015, 19:23
Lokalizacja: USA
Kontaktowanie:

Re: [PC] Przeglądanie plików w C

Postautor: WoodPaker » wtorek 20 paź 2015, 00:38

Ooo. podoba mi się:)
Sprawdzę wieczorem czy dziala. Dziękuję
Life is to short to eject USB safely

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

Re: [PC] Przeglądanie plików w C

Postautor: mokrowski » środa 21 paź 2015, 00:51

Masz tu kod:

Kod: Zaznacz cały

#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <exception>
#include <regex>

using namespace std;

pair<size_t, string> back_position_and_line(ifstream& file,
        size_t file_size, size_t current_position = 0) {
    char c;
    vector<char> char_vector;
    auto position = current_position;
    while(position <= file_size) {
        position++;
        file.seekg(-position, ios::end);
        file.get(c);
        char_vector.push_back(c);
        if (c == '\n' || position == file_size) {
            auto line = string(char_vector.rbegin(), char_vector.rend());
            line.erase(remove(line.begin(), line.end(), '\n'), line.end());
            return { position, line };
        }
    }
    // File size 0 bytes..
    return {0, ""};
}

pair<size_t, size_t> get_position_backward(const string& file_path, const string& pattern) {
    // Set cursor to end of file, binary, input.
    auto file = ifstream(file_path, ios::ate | ios::binary | ios::in );
    if(!file.is_open()) {
        string throw_msg("File ");
        throw_msg += file_path + string(" open error.");
        throw logic_error(throw_msg);
    }

    size_t file_size = file.tellg();
    auto pattern_regex = regex(pattern, regex::extended);
    smatch sm;

    pair<size_t, string> result{};
    do {
        result = back_position_and_line(file, file_size, result.first);
        regex_match(result.second, sm, pattern_regex);
        if(sm.position(1) < result.second.length()) {
            return {file_size - (result.first - sm.position(1)) + 1, file_size };
        }
    } while(result.first < file_size);
    // No match :-(
    return {file_size, file_size};
}

int main(void) {
    // matched "HF=2131.33XXXXMP2=-212.3312"
    string search_rgxp="^.*(HF=(-?)[0-9]*\\.[0-9].*MP2=(-?)[0-9]*\\.[0-9].*).*$";
    auto position = get_position_backward("e-1-h2o.out", search_rgxp);
    if(position.first == position.second) {
        cout << "No match!" << endl;
        exit(0);
    }

    // Fast and dirty check...
    ifstream file = ifstream("e-1-h2o.out");
    file.seekg(position.first, ios::beg);
    char c;
    for(; c != '\n'; file.get(c)) {
        cout << c;
    }
    cout << endl;
}

Jak mówiłem, w trybie komercyjnym pewnie jeszcze bym coś z tym robił ale Ty chciałeś jedynie pomocy.
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

Awatar użytkownika
WoodPaker
User
User
Posty: 136
Rejestracja: czwartek 17 wrz 2015, 19:23
Lokalizacja: USA
Kontaktowanie:

Re: [PC] Przeglądanie plików w C

Postautor: WoodPaker » środa 21 paź 2015, 04:11

Podoba mnie się ten kod. Chociaż i tak będzie/zostanie przerobiony z powodu, że nie zawsze wystepuje tekst MP2, a i HF lubi sobie różnie inaczej występować. Ale to już jakiś zysk.
W każdym razie wczoraj zanim dostałem dzisiajszą odpowiedź od Ciebie poradziłem sobie tak, że czytam od początku wszystkie HF'y, a nastepnie po zakończeniu czytania pliku biore ostatni wczytany. Ot i się rozwiązało
Podziękował śliczniasto
Life is to short to eject USB safely


Wróć do „Pisanie programów w C”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość