Java fájlkezelés kérdés

Olvasgatom a java fájlkezeléséről szóló infókat. Eddig ami lejött: vannak szöveges fájlok, amikben szöveg van és vannak bináris fájlok, amikben számok (durván). Olyan nincs, hogy egy fájlban egyszerre szöveg és szám? Bár gondolom, ezt valahogy bináris formátumban kellene elkészíteni.

Hozzászólások

Ennek a kérdésnek nem sok köze van a java-hoz....

Konzervatív embereknek: s/fájl/file/g, s/bájt/byte/g

Valójában fájlból csak egyféle van: bájtsorozat.
Hogy ezt a bájtsorozatot esetleg (valamilyen kódolás szerinti, pl. UTF-8) "betűsorozatnak" (=szöveges fájl) vagy bináris értékek sorozatának tekinted-e, az már teljesen rajtad múlik. Ahogyan azt a kollégák pontosan leírták, ugyanazt a dolgot, pl. az ASCII 'A' betűt tekintheted 65-nek is. És mivel a fájlok nem típusosak, sosem lehet tudni, hogy az író mit is akart mondani.

Fuszenecker_Róbert

Az OK, hogy egy fájlban technikailag mi van. A Java viszont attól függően, hogy mit akarok kiolvasni, kétféle lehetőséget kínál fel - vagy bináris halmazként, vagy karakterhalmazként tekinti azt. Azóta viszont megkaptam a választ a problémámra.
--
Fight / For The Freedom / Fighting With Steel

Egyetertek az elottem szoloval, annyit tennek hozza, hogy jo otlet lenne masik java konyvet olvasgatni akkor.

Java-ra vonatkozóan: két féle blokkoló I/O-t különít el: a byte alapút (ez a InputStream/OutputStream család) és a karakter alapút (ezek a Reader-ek és Writer-ek). A két library (időben először voltak a Stream-ek és talán 1.1-től vannak Writerek, valaki majd kijavít) viszonylag szépen ki vannak találva és jól meg vannak szerkesztve, a Reader/Writer családra konvertálhatók a Stream-ek (InputStreamReader, OutputStreamWriter).

Ami az igazi különbség a kettő között (és ez szépen látszik az ISR és OSW konstruktoraiból), hogy a Reader/Writer család egy adott karakterkódolás szerint értelmezi a bájthalmot, ha nem adsz meg mást, akkor az OS/locale-től függő karakterkódolással - rosszul.

Ez már mondjuk nem tartozik a kérdéshez, de ne magadtól kelljen rájönnöd: az egész API a decorator mintára épül, a néhány "végső" Stream/Reader/Writer (fájl, socket, memória, standard cuccok) köré tudsz kiegészítőket pakolni, pl. buffered olvasás (BufferedInputStream, BufferedReader, ...)

Szerk.: Ja, igen, és hogy a kérdésedet meg is válaszoljuk. Bőven tudsz olyat csinálni, hogy mondjuk 10 bináris bájt után 6 UTF-8 karakter (így ugye egy rekord min. 16 max 34 byte), felolvasod az InputStream-ről a 10 byte-ot, utána ugyanarra a FileInputStream-re aggatott Reader-ből a 6 karaktert.

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

És egy példakód is:


import java.io.*; /* File[In|Out]putStream, OutputStreamWriter, InputStreamReader */
import java.nio.charset.Charset;
import java.util.*; /* Arrays */

class Test {

        public static void main(String args[]) throws Exception {
                        /* Kiírás */
                FileOutputStream fileOut = new FileOutputStream("test.dat");
                Writer writer = new OutputStreamWriter(fileOut, Charset.forName("UTF-8"));
                fileOut.write(new byte[] { 1, 2, 3, 4 });
                writer.write("Hello!", 0, "Hello!".length());
                writer.close();
                fileOut.close();
                        /* Beolvasás */
                byte array[] = new byte[4];
                char msg[] = new char[6];
                FileInputStream fileIn = new FileInputStream("test.dat");
                Reader reader = new InputStreamReader(fileIn, Charset.forName("UTF-8"));
                fileIn.read(array);     /* Remélhetőleg 4 byte-ot be is olvasunk, illik ellenőrizni */
                System.out.println(Arrays.toString(array));
                reader.read(msg, 0, 6);
                reader.close();
                fileIn.close();
                System.out.println(new String(msg));
        }

}

(Persze az összes inicializálás szebb lenne try-with-resource blokkal, most ennyire futotta :))

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

Aham. És ha sorrendben egy karakter, egy szám és két bit van, akkor


int number;
char character;
boolean bool[]=new boolean[2];
reader.read(character);
fileIn.read(number);
fileIn.read(bool);

(Most a paraméterlistától tekintsünk el...)
--
Fight / For The Freedom / Fighting With Steel

A primitív típusok közül csak byte-ot és char-t tudsz olvasni, a többinél játszanod kell (pl. int-nél beolvasol négy bájtot, és shifteled aztán or-ozod őket, boolean-nél valami bájtot meg kell feleltetned a két értéken). Itt már érdemes lehet a képbe hozni a NIO-t (Java 1.5-ös fejlemény), egész pontosan a ByteBuffer-t. Ezzel egyszerűen meg tudod csinálni a konverziót byte tömbbé, azt pedig már tudod kezelni a Stream-ben (Igazából az egész NIO egy nagyon erős library, de amíg nincs rá kifejezetten szükséges [pl. aszinkron I/O-t akarsz csinálni Java-ból], szerintem kerüld el :) ):


ByteBuffer buffer = ByteBuffer.allocate(6); /* 4 byte az int-nek, egy-egy bool-nak */
buffer.putInt(123456);
buffer.put(bool[0] ? (byte) 1 : (byte) 0); /* Nincs putBool */
buffer.put(bool[1] ? (byte) 1 : (byte) 0);
fileOut.write(buffer.array());

És a visszaolvasás:


byte data[] = new byte[6];
fileIn.read(data);
ByteBuffer buffer = ByteBuffer.wrap(data);
System.out.println(buffer.getInt());
System.out.println(buffer.get() == 0 ? true : false);
System.out.println(buffer.get() == 1 ? true : false);

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)