Edytowanie/Modyfikacja pliku txt (lub innego)

0

Witam
Mam pytanie odnośnie modyfikacji pliku txt.
Mój plik txt jest w postaci ciągu kolejnych liczb typu long (8 bajtowych). Odczytanie np. 3 liczby jest proste bo InputStream ma metodę "skip", więc wykonanie na strumieniu "skip(16)" i potem rozpoczęcie czytania daje mi 3 liczbę typu long. Problem jest z tym jak zmodyfikować jakąś liczbę w środku (nie dopisywać do końca)? Czy można to zrobić bez przepisywania pliku? Czy analogicznie można też skasować wybrany fragment bajtów? ew. może to być inny format pliku niż txt.

Pozdrawiam

0

Musisz pisać cały plik, a dokładniej to musisz zapisać od pozycji zmiany do końca.

0

Ale czy na prawdę nie ma jakiegokolwiek sposobu? Czy w ogóle jest język, który coś takiego oferuje? Bo właśnie problem z tym, że te dane mogą być dosyć ogromne i przepisywanie wszystkiego mogłoby trwać dosyć długo.

0

Może jakaś baza danych.

0

Memory mapped file

0

Zainteresuj się buforami i new i/o. Ta od wersji 7 daje takie możliwości aby zapisywać wycinek pliku tekstowego o wielkości jednego klastra, czyli w zależności od systemu i dysku 512 B lub 4 KB (ale trzeba napisać troszkę kodu, żeby mieć aż taką kontrolę). Obecnie obsługa plików w Javie jest tak niskopoziomowa jak to możliwe bo używane są mechanizmy direct access czyli w praktyce DMA. Robione jest to oczywiście przezroczysto poprzez nowe klasy obsługi plików i buforów i ich mapowanie przez jvm na api systemu. Wystarczy ogarnąć trochę standardowego javadoca.

1

@Olamagato zaciekawilo mnie co napisales o bezposrednim dostepie do urzadzen blokowych z Javy, bo nigdy o czyms takim nie slyszalem. Mozesz podac wiecej szczegolow?
@Parker mozesz slyszec rozne szalone sugestie, ale ja zaczalbym od rozwiazan przeznaczonych do takich zadan, czyli pliki mapowalne w pamieci (np. RandomAccessFile)

0
wojciech.kudla napisał(a):

@Olamagato zaciekawilo mnie co napisales o bezposrednim dostepie do urzadzen blokowych z Javy, bo nigdy o czyms takim nie slyszalem. Mozesz podac wiecej szczegolow?

Oczywiście. Rzuć okiem na dokumentację klasy ByteBuffer i jej metody allocateDirect, a następnie na metody FileChannel.read i write. Alokowanie buforów wielkości bloków urządzenia lub jednostki alokacji plików pozwala na niskopoziomową obsługę zapisów i odczytów, a tym samym również na pełną kontrolę zapisywania i odczytywania poszczególnych sektorów dysku ponieważ plik jest alokowany zawsze od początku jakiegoś sektora dyskowego. Problem polega tylko na tym, że jeżeli kodowanie znaków nie daje odwzorowania 1:1 tak jak np. w UTF-8, to trzeba przed każdym zapisem używać metody Charset.encode(CharBuffer cb) dającej w wyniku zakodowany ByteBuffer (o innej długości niż CharBuffer dla UTF-8), a po odczycie Charset.decode(ByteBuffer bb) dający w wyniku odkodowany CharBuffer. Oczywiście kodowanie jest ze standardowego w pamięci JVM kodowania UTF-16LE (little endian) do wybranego, a dekodowanie odwrotnie, do UTF-16LE.
Dlatego, żeby to ogarnąć trzeba napisać trochę swojego kodu, który umożliwi wygodne zapisywanie i odczytywanie dowolnego kawałka tekstu do i z pliku.
[Aktualizacja]
Kodowanie i dekodowanie CharBuffera jest oczywiście obowiązkowe dla wszystkich rodzajów kodowań. Nie trzeba tego robić tylko w wypadku kodowania pliku tekstowego na UTF-16LE i odwrotnie. Można też kodować przed każdym zapisem jeden Charbuffer obejmujący cały tekst i wyjściowego ByteBuffera podzielić na mniejsze i każdy z nich zapisywać w razie potrzeby wcześniej używając metody FileChannel.position.

0

@Olamagato
Wydaje mi sie ze mylisz pojecia. ByteBuffer.allocateDirect() nie ma nic wspolnego z jakimkolwiek dostepem do dysku. Jedyna konsekwencja jego wywolania jest zaalokowanie bloku pamieci przy pomocy malloc. To samo w przypadku mmap, ktore jvm stosuje dla memory mapped files.
Kodowanie znakow nie ma tutaj nic do rzeczy.

0

Pamięć jest alokowana przez mechanizmy systemu właśnie po to aby operacja dyskowa była przeprowadzana sprzętowo przez kontroler DMA, a nie programowo za pomocą procedury wykonywanej przez CPU. Jest to nic innego jak bezpośredni dostęp do dysku. Od JVM 7 żaden program Java napisany z użyciem nowego API nie może być mniej wydajny jeżeli chodzi o operacje dyskowe od kodu natywnego takiego jak napisany w C/C++. Natomiast kodowanie znaków nie ma z tym nic wspólnego, to oczywiste.
[Aktualizacja]
Oczywiście bufory alokowane bezpośrednio nie muszą wcale być wielkościami sektorów czy jednostek alokacji plików. API systemu też tego nie wymaga. Różnica między alokowaniem bezpośrednim, a nie bezpośrednim jest tylko taka, że pomijany jest krok przepisywania przez kod systemu (czyli CPU) bufora na stercie JVM do prywatnego obszaru systemowego na który jest zaprogramowany kontroler DMA w taki sposób, że po przeprogramowaniu kontroler ten operuje bezpośrednio na pamięci RAM dostępnej dla kodu Javy/JVM (bez znaczenia czy w danym momencie skompilowanego w locie do kodu maszynowego czy kodu maszynowego JVM interpretującego bytecode). Oczywiście przeprogramowanie jest standardową procedurą dostępną dla natywnego kodu maszynowego, natomiast Java we wcześniejszych wersjach pracowała podobnie jak procedury DOS/BIOS zawierające krok przepisywania danych przez CPU. Jest to niewydajne. Szczególnie dla dużych ilości danych na jakich operuje się obecnie.

0

Pamięć jest alokowana przez mechanizmy systemu właśnie po to aby operacja dyskowa była przeprowadzana sprzętowo przez kontroler DMA, a nie programowo za pomocą procedury wykonywanej przez CPU. Jest to nic innego jak bezpośredni dostęp do dysku.

Dobrze byloby gdybys poznal roznice pomiedzy malloc a mmap, bo ewidentnie mylisz pojecia.

Od JVM 7 żaden program Java napisany z użyciem nowego API nie może być mniej wydajny jeżeli chodzi o operacje dyskowe od kodu natywnego takiego jak napisany w C/C++.

A mozesz opisac w jaki sposob Java realizuje te gwarancje? Ja np. do tej pory wiele funckjonalnosci osiagam przez wywolania jni, bo Java nie oferuje wielu optymalizacji. Zabawki takie jak lock xadd albo cmov dla inkrementacji atomicow pojawily sie dopiero w Java 8.

[Aktualizacja]
Oczywiście bufory alokowane bezpośrednio nie muszą wcale być wielkościami sektorów czy jednostek alokacji plików. API systemu też tego nie wymaga. Różnica między alokowaniem bezpośrednim, a nie bezpośrednim jest tylko taka, że pomijany jest krok przepisywania przez kod systemu (czyli CPU) bufora na stercie JVM do prywatnego obszaru systemowego na który jest zaprogramowany kontroler DMA w taki sposób, że po przeprogramowaniu kontroler ten operuje bezpośrednio na pamięci RAM dostępnej dla kodu Javy/JVM (bez znaczenia czy w danym momencie skompilowanego w locie do kodu maszynowego czy kodu maszynowego JVM interpretującego bytecode). Oczywiście przeprogramowanie jest standardową procedurą dostępną dla natywnego kodu maszynowego, natomiast Java we wcześniejszych wersjach pracowała podobnie jak procedury DOS/BIOS zawierające krok przepisywania danych przez CPU. Jest to niewydajne. Szczególnie dla dużych ilości danych na jakich operuje się obecnie.

  1. Bufory na stercie sa niemapowalne na pliki. Nie wiem skad pozyskales wiedze ze sa.
  2. Do skorzystania z DMA nie jest potrzebne zadne "przeprogramowanie". To juz jakas kompletna bzdura.
  3. Zero-copy data transfer jest w Javie dostepny od 1.5 poprzez NIO (zwlaszcza bufory i channele).

Twoje posty brzmia jakbys wiedzial o czym mowisz, ale ewidentnie miesza ci sie kilka tematow jednoczesnie. Pomysl o tym w ten sposob: ktos poczatkujacy przeczyta sobie takiego posta i bedzie mial bledne przekonanie o tym jak rzeczy w Javie dzialaja.
Z checia podesle liste dobrych lektur na poczatek, ktore pomoglyby ci uporzadkowac wiedze, ktora juz masz.

0

Dobrze byloby gdybys poznal roznice pomiedzy malloc a mmap, bo ewidentnie mylisz pojecia.

Ujmę to tak. Ostatni raz pisałem kod w C obsługujący operacje dyskowe z bezpośrednim żądaniem do kontrolera DMA w 1992 r.
I na pewno nie mylę żadnych pojęć bo szczegóły wirtualizacji pamięci i plików i urządzeń o których raczyłeś wspomnieć, to zupełnie inna bajka i z zupełnie innej epoki.

A mozesz opisac w jaki sposob Java realizuje te gwarancje?

No cóż. :-) Tak jak jest napisane:
http://docs.oracle.com/javase/7/docs/api/java/nio/ByteBuffer.html
Ale ponieważ to wytłumaczenie jest dla "specjalistów" z drugiej dekady 21. wieku, więc nie ma tam żadnej informacji o tym, że operacje dyskowe są w komputerach PC od mniej więcej 30 lat wykonywane za pomocą urządzenia innego niż CPU. I jak na razie to się nie zmieniło. A to, że współcześnie jest to schowane głęboko w systemie i wszystko robi za Ciebie API systemu, a na nim API Javy, to już zupełnie inna sprawa.
[Uwaga, archeologia, bezużyteczna dla osób znających tylko Javę :-)]
Tak przypadkiem to DMA, który jest sprzętowym kontrolerem też musi zostać zaprogramowany zanim cokolwiek robi. I znowu przypadkiem obecnie robi to jedna z niskich warstw systemu. Ale za czasów gdy istniał jeszcze BIOS, znano takie pojęcia jak PIO i DMA oraz pracowało się w trybie rzeczywistym CPU - nie robiła tego systemowa procedura API, lecz każdy musiał sobie samemu zaprogramować porty kontrolera, żeby mieć szybki i niezależny od obciążenia procesora transfer dyskowy. Bo miałeś dostępnego tylko DOSa (i Xenixa, ale mało kto to miał).
Fakt, że jest to zamierzchła przeszłość i archeologia, ale jeżeli tego się nie wie, to nie można naprawdę zrozumieć wpływu bezpośredniego alokowania bufora w pamięci (i to fizycznej), na to jak program wykonywany przez JVM przeprowadza operacje dyskowe. Dlatego w javadocu jest tylko formułka sprowadzająca się do tego, że "tak jest lepiej".
Być może nie będzie się tego rozumiało jeżeli samodzielnie nie spróbuje się napisać sterownika dyskowego. Albo jeszcze lepiej procedury I/O operującej na sprzęcie z pominięciem systemu (choć w trybie chronionym CPU nie jest to realnie możliwe).

  1. Bufory na stercie sa niemapowalne na pliki. Nie wiem skad pozyskales wiedze ze sa.

Zaraz. Zaczynam mieć wrażenie, że mówimy o czymś zupełnie innym. Prosiłbym, żebyś nie wciskał mi żadnych rzeczy, których nie napisałem.
Napisałem tylko, że jeżeli masz ochotę, to możesz sobie sam na piechotę mapować dowolny plik na zarządzane przez siebie bufory. I tylko to. A jeżeli jednak upierasz się na pliki mapowane na pamięć, to jak najbardziej Java NIO też to przecież ma. Ale jest to tak jak napisałem - skrót zrobiony dla wygody - bezużyteczny dla obsługi bezpośredniego zapisu wycinków pliku tekstowego (chyba, że będą to pliki z kodowaniem natywnym JVM, czyli UTF-16LE).

  1. Do skorzystania z DMA nie jest potrzebne żadne "przeprogramowanie". To juz jakas kompletna bzdura.

To dla mnie trochę śmieszne, ale jeżeli nie wiesz, że różne sprzętowe kontrolery się programuje zanim wykonają dla Ciebie jakąś pracę, to w zasadzie ciężko o jakiś wspólny punkt zaczepienia. Dzisiaj rzeczywiście nie jest potrzebne programowanie sprzętu bo robi to za Ciebie metoda z API Javy, a za nią kolejne warstwy JVM, następnie API systemu, a już na szarym końcu sterownik systemu. Ale, to że coś robi to za Ciebie nie zmienia faktu, że każda operacja dyskowa składa się z dwóch elementów: Przygotowania bufora, a następnie zaprogramowania kontrolera żeby dane zostały przez niego wczytane lub zapisane. Finito. Tylko wtedy nie musisz czekać na operację dyskową i kod leci sobie w wątku dalej.

  1. Zero-copy data transfer jest w Javie dostepny od 1.5 poprzez NIO (zwlaszcza bufory i channele).

Racja, a nawet od 1.4. Ale mi chodziło o NIO2, które dopiero od tej edycji jest użyteczne do obsługi np. plików tekstowych. Dopiero od Javy 7 API operacji I/O Javy jest "współczesne" i kompletne. I sam dopiero od tej wersji zacząłem używać w Javie wydajnych operacji dyskowych bo wcześniej było to średnio użyteczne.
http://en.wikipedia.org/wiki/Non-blocking_I/O_%28Java%29#JDK_7_and_NIO.2
Polecam szczególnie akapit "Channels".

Myślę, że jednak wiem o czym mówię. :P
I nie sądzę, że coś mi się miesza. Aż tak jeszcze nie zdziadziałem... :-)
Ale chętnie dowiem się że istnieje jakaś książka, której jeszcze nie udało mi się przeczytać.
Pozdrawiam.

1 użytkowników online, w tym zalogowanych: 0, gości: 1