[C++] Wczytywanie pliku z buforowaniem
Ostatnio zmodyfikowano 2024-04-03 20:33
idepozapalki Temat założony przez niniejszego użytkownika |
[C++] Wczytywanie pliku z buforowaniem » 2024-04-02 23:40:48 Dzień dobry, Zainspirowany trochę kursem chciałem poskładać cegiełki i użyć elementów do wczytywania dużych plików z buforowaniem z użyciem elementów z bibliotek. Mój zamysł jest taki żeby otworzyć plik przy użyciu ifstream, następnie wczytywanie go po kawałku do stringstream i w końcu pobraniu linii przy użyciu getline. Moja piaskownica w której sobie testuje i wyciągam jakieś wnioski: #include <fstream> #include <iostream> #include <sstream>
class file1 { public: int filesize; int chunksize = 2048; std::ifstream file; std::stringstream ss; std::streamsize s; file1() { file.open( "test.txt", std::ios::binary | std::ios::ate ); filesize = file.tellg(); file.seekg( 0, std::ios::beg ); std::cout << filesize << " Bytes" << '\n'; std::cout << "Koniec!\n"; } void ladujbufor() { char * buffer = new char[ chunksize ]; file.read( buffer, chunksize ); ss.write( buffer, chunksize ); delete[ ] buffer; std::streamsize a = file.gcount(); } std::string getLine() { std::string line; std::getline( ss, line ); int sssize = ss.tellg(); return line; } void czysc() { int sssize = ss.tellg(); ss.ignore( sssize ); sssize = ss.tellg(); } ~file1() { file.close(); } };
int main() { file1 f1; f1.ladujbufor(); f1.ladujbufor(); std::cout << f1.getLine() << '\n'; f1.czysc() f1.getLine(); f1.ladujbufor(); }
Oczywiście jest to wersja w najprostszej postaci bez obsługi błędów i uproszczona do bólu. Po co to robię? Bo samo wczytanie pliku tekstowego do bufora w całości zajmuje u mnie ponad minutę i jest to czas w którym właściwie nic poza tym się nie dzieje. Dlatego użyłem tego to read i write. To co sprawia mi problemy to właściwie 2 rzeczy: 1. metoda ladujbufor() powoduje za każdym wywołaniem dołożenie do stringstream ss kolejnego fragmentu z pliku. Widać to w debugerze podglądając zawartość ss. Chciałbym w jakiś sposób wyczyścić metodą czyść() początek stringstramu z którego pobrałem linię metodą getLine(), bo dokładanie kolejnych fragmentów metodą ladujbufor() powoduje, że ss "puchnie". 2. Używanie getLine() niesie ze sobą niebezpieczeństwo że w którymś momencie dojdę do końca bufora i nie znajdę końca linii. Czy da się coś z tym zrobić? Zachować ten kawałek bez \r\n Oczywiście przeglądałem net i takiego gotowca nie znalazłem. Czy takie podejście ma sens czy muszę to rozwiązanie uzbroić w dodatkowe elementy, że zadziałało. |
|
DejaVu |
» 2024-04-03 09:36:33 Chat GPT: Dzień dobry! Twój pomysł na buforowanie danych podczas czytania dużych plików jest bardzo sensowny, szczególnie gdy mamy do czynienia z sytuacjami, w których odczyt całego pliku naraz jest nieefektywny lub niemożliwy z powodu ograniczeń pamięciowych. Twoje podejście do rozwiązania problemu jest na dobrym kierunku, ale pozwolę sobie na kilka sugestii, które mogą pomóc Ci w udoskonaleniu kodu.
### Optymalizacja metody `ladujbufor()`
Metoda `ladujbufor()` jest kluczową częścią Twojego rozwiązania, ale wydaje się, że nie bierzesz pod uwagę przypadku, gdy odczytane z pliku dane są mniejsze niż `chunksize`. To może być problematyczne, zwłaszcza przy ostatnim fragmencie pliku. Możesz to naprawić, korzystając z `file.gcount()` do zapisania tylko rzeczywistej liczby przeczytanych bajtów do `stringstream`:
```cpp void ladujbufor() { char * buffer = new char[chunksize]; file.read(buffer, chunksize); // czytaj z pliku blok znakow std::streamsize bytesRead = file.gcount(); // rzeczywista liczba przeczytanych bajtów ss.write(buffer, bytesRead); // zapisz tylko przeczytane bajty delete[] buffer; } ```
### Czyszczenie `stringstream`
Rozumiem, że chcesz "wyczyścić" `stringstream` z danych, które już zostały przetworzone. Jednak sposób, w jaki próbujesz to zrobić (`ss.ignore(sssize);`), nie działa tak, jak oczekujesz. `stringstream` nie jest zaprojektowany do "usuwanie" danych z początku strumienia w łatwy sposób. Jednym z rozwiązań jest przechowywanie nieprzetworzonych danych w innym `stringstream` po każdym odczycie linii:
```cpp void przepiszNieprzetworzone() { std::string reszta; std::getline(ss, reszta, '\0'); // Pobierz wszystko do końca jako jedną linię ss.str(""); // Wyczyść strumień ss.clear(); // Resetuj stan strumienia ss << reszta; // Wstaw resztę danych z powrotem do strumienia } ```
### Obsługa końca linii w buforze
Rozwiązanie problemu z końcem linii, który może nie pojawić się w buforze, wymaga bardziej złożonego podejścia. Jednym ze sposobów jest przechowywanie niezakończonej linii między wywołaniami `ladujbufor()`, a następnie łączenie jej z następną porcją danych, aby zapewnić ciągłość. Można to osiągnąć przez dodanie zmiennej członkowskiej klasy, która będzie przechowywać niezakończoną linię, i modyfikację `getLine()` oraz `ladujbufor()`, aby obsługiwały ten przypadek.
### Podsumowanie
Twoje podejście ma sens, ale wymaga kilku modyfikacji, aby poprawnie obsługiwać przypadki brzegowe i usprawnić zarządzanie pamięcią. Zastosowanie się do powyższych sugestii powinno pomóc w osiągnięciu celu efektywniejszego czytania dużych plików. Jeśli masz jakiekolwiek pytania lub potrzebujesz dalszej pomocy, daj znać!
|
|
idepozapalki Temat założony przez niniejszego użytkownika |
» 2024-04-03 20:33:39 Dziękuję bardzo, za podpowiedź. Nawet nie brałem tego pod uwagę. Bardzo podoba mi się ten kierunek. |
|
« 1 » |