JavaRush /Blog Jawa /Random-JV /Byte-by-byte karya karo file
Joysi
tingkat

Byte-by-byte karya karo file

Diterbitake ing grup
Khusus kanggo

Ayo dadi miwiti

Ing level 18, tugas pisanan maca file byte-by-byte diwiwiti: maca file kasebut, banjur golek bita minimal/maksimum utawa output ing wangun sing diurutake, lsp.
Karya byte-by-byte karo file - 1
Wong kene pinter banget. Dheweke ngerti babagan koleksi lan bisa diurutake lan dilebokake. Koleksi minangka mekanisme sing kuat. Lan akeh sing ora nggunakake sadurunge JavaRush. Mesthi wae, kudu dipuji yen sinau lan nyoba kanggo mencet ing panggonan sing salah. Dadi. Ayo njupuk masalah sing ora ana ing tugas (supaya ora ana spoiler nalika ngrampungake), nanging ana sing padha:
  • Ketik jeneng file saka console
  • Maca kabeh bita saka file.
  • Nglirwakake pengulangan, urutake miturut bytecode kanthi urutan mudhun.
  • Tampilan
  • Nutup stream I/O
Conto byte file input 44 83 44 Conto output 83 44 Kita uga ngenalaken variabel startTimelan finishTimekanggo ngrekam wektu eksekusi program. Kanggo pitungan aku digunakake i3-3GHz / 8Gb RAM / HDD WD Blue-1Tb / Win7-64 / jdk-8u73-windows-x64 (conto program ing opsi 1-2 dijupuk saka forum info.javarush, padha rada diowahi mung kanggo ngurutake kanthi urutan munggah oke - yaiku, REAL !!)

Ayo rampungake kanthi langsung:

// Вариант 1. Загоняем в коллекцию и сортируем используя ее метод Collections.sort
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());
        long startTime = System.currentTimeMillis();

        ArrayList<Integer> listData = new ArrayList<Integer>();
        while (inputStream.available() > 0) listData.add(inputStream.read());
        inputStream.close();
        ArrayList<Integer> result = new ArrayList<Integer>(new HashSet<Integer>(listData));
        Collections.sort(result);

        while (!result.isEmpty()) {
            System.out.print(result.get(result.size()-1) + " ");
            result.remove(result.get(result.size()-1));
        }

        long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}
Ngatasi kabeh sing apik! Tes (yen wis ana, mesthi lulus kanthi bang). Nanging ing urip ana sawetara file sing mung ngemot baris "Ibu wisuh pigura." Ayo dadi feed program kita file 46MB (miturut standar saiki, ora katon kaya akeh). Apa iku, program mbukak kanggo 220 detik. Usaha kanggo feed file 1Gb ing wayah sore (ukuran film MPEG4 ora kualitas paling apik) ora kasil. Aku isih maca program kasebut ing wayah esuk - lan aku kudu kerja. Apa masalahe? Mbokmenawa digunakake ArrayList<Integer>sing nduweni 1 milyar unsur ing njero. Saben unsur njupuk minimal 16 bita (Header: 8 bait + Field int: 4 bait + Alignment kanggo multiplicity 8: 4 bait). In total, kita tanpo pekso sijine 16 Gb data menyang memori karo ukuran RAM 8. Kita bakal nindakake luwih apik. Ayo nyilem luwih jero menyang koleksi. Lan hurray, kita nemokake apa sing dibutuhake.

Ketemu TreeSet

Iki akeh:
  • ora ngidini nyimpen rong unsur sing padha (sing tegese kita bakal nyimpen kabeh 255 unsur ing memori, tinimbang milyar!)
  • nalika manipulasi unsur-unsur kasebut, kanthi otomatis ngatur (ngurutake dhewe - ing kene, dhuwure kesempurnaan!)
Kita entuk:
// Вариант 2. Загоняем в ТreeSet который сам сортирует (лютый win!)
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        byte[] arrBytes = new byte[256];
        long startTime = System.currentTimeMillis();

        SortedSet<Integer> list = new TreeSet<Integer>();
        while(inputStream.available()>0) list.add(inputStream.read());
        inputStream.close();

        while (!list.isEmpty())        {
            System.out.print(list.last() + " ");
            list.remove(list.last());
        }

		long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}
Output yaiku: file 46MB, 176 detik. File 1Gb - 3 jam 5 menit. Kemajuan ketok. Kita bisa "ngenteni" asil, lan file 46MB diproses luwih cepet. Terusna. Ayo nyoba nyerahake koleksi (iki bakal nglarani banget kanggo sawetara). Kita bakal nggunakake array prasaja (iku primitif banget). Ayo dicathet siji sing penting . Jumlah bait sing ditemoni bisa dilebokake ing array sing dawane 256. Dadi, kita mung nambah unsur array sing cocog karo bait sing diwaca kanthi siji.

Array - byte byte

// Вариант 3. Считываем массив поbyteно.
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        long[] arrBytes = new long[256];
        long startTime = System.currentTimeMillis();

        while (inputStream.available() > 0) arrBytes[inputStream.read()]++;

		inputStream.close();
        // Выводим отсортированный по byte-codeу в обратном порядке
        for (long i = 255; i >= 0 ; i--)
            if (arrBytes[(int) i] > 0) System.out.print(i + " ");

			long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}
Output yaiku: file 46MB, 158 detik. File 1Gb - 2 jam 55 menit. Maneh dandan, nanging cilik. Lan kita nindakake kabeh kanthi alat sing prasaja. Ora nggunakake mikroskop kanggo nyopir kuku . Saiki digression lirik. Ayo dadi elinga struktur komputer. memori RAM (DRAM) , ngendi program biasane kaleksanan lan variabel disimpen, nduweni kacepetan akses dhuwur, nanging ukuran cilik. Memori ing hard / flash drive (HDD utawa Flash drive) ngendi file biasane disimpen, ing nalisir, nduweni kacepetan akses kurang nanging ukuran gedhe. Dadi nalika maca file 1Gb byte byte (yaiku, kita ngakses HDD kaping milyar), kita nglampahi akeh wektu kanggo nggarap piranti kacepetan rendah (kita nransfer gandum wedhi kanthi gandum saka awak truk KamAZ. menyang sandbox). Ayo dadi nyoba kanggo nambah luwih.

Ayo mbucal kabeh truk KAMAZ kanthi wedhi bebarengan!

// Вариант 4. Считываем массив сразу целиком за раз в память.
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        long[] arrBytes = new long[256];
        long startTime = System.currentTimeMillis();

        byte fileImage[]=new byte[inputStream.available()];
        long fileSize=fileImage.length;
        inputStream.read(fileImage);
        for (int i = 0; i = 0 ; i--)
            if (arrBytes[(int) i] > 0) System.out.print(i + " ");

		long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}
digression cilik, nanging maneh penting .
  1. indeks arrBytes ditetepake ing 0..255,
  2. fileImage minangka array byte sing unsur duweni nilai -128..127
Mulane, kanggo count bita, kita bakal nggunakake construction arrBytes[fileImage[i] & 0b11111111]++; sing mung bakal ngreset bit tandha lan bali kita Nilai ing sawetara 0..255 Lan, asil: 46MB file 0.13 detik (kurang saka detik). File 1Gb - 9 detik. Kita nindakaken! Kita luar biasa kelangan! Dicepetake saka 3 jam nganti 9 detik. Wis, sampeyan bisa lungguh ing kursi lan ngombe teh. Lan saiki eksperimen liyane - ayo nyoba file 32 Gb (contone, film HD). Akibaté, kita njaluk swara crackling saka HDD apa karo program nabrak ing Windows. KamAZ mbuwang awak nganggo wedhi lan nyuwil kothak wedhi! Apa sing kita lakoni? Ayo ngelingi siji fakta maneh. File ing OS biasane disimpen ing bagean (kluster) 2-64Kb (gumantung saka jinis sistem file, setelan, lsp). Kita bakal maca ing bagean, contone 64.000 bita. Ayo nyoba mbongkar KamAZ karo excavator ing bagean sing cukup gedhe:

Nggunakake buffer

// Вариант 5. Считываем массив кусками.
public class Solution {
    public static void main(String[] args) throws Exception {
        FileInputStream inputStream = new FileInputStream(new BufferedReader(new InputStreamReader(System.in)).readLine());

        long[] arrBytes = new long[256];
        long startTime = System.currentTimeMillis();

        int  bufferSize = 64000;
        byte buffer[]   = new byte[64000];

        while (inputStream.available() > 0) {
            if (inputStream.available() < 64000) bufferSize = inputStream.available();
            inputStream.read(buffer, 0, bufferSize );
            for (int i = 0; i = 0 ; i--)
            if (arrBytes[(int) i] > 0) System.out.print(i + " ");

		long finishTime = System.currentTimeMillis();
        System.out.println("\nвремя работы=" + (finishTime-startTime) + "ms.");
    }
}
Akibaté, kita entuk: 46MB file 0,08 detik (kurang saka detik). File 1Gb - 0,9 detik (kurang saka detik). File 32Gb - 31 detik. Elinga yen kanggo file 1 Gb kita wis nambah kinerja saka sawetara jam kanggo pecahan detik !!! Kanthi kasunyatan sing sederhana iki, kita bakal ngrampungake eksperimen lan nambah kode awal. Kita wis nggawe kemajuan kanthi pirang-pirang cara - kita seneng karo indikator konsumsi memori lan wektu operasi anyar. Uga, ing kasus iki, kita ora narik koleksi sing ora ana guna saka perpustakaan standar. PS Ana sing bakal ngomong contone adoh, lsp. Nanging ana akeh tugas sing padha - kanggo nganalisa volume gedhe saka unsur sing duwe nomer winates saka negara. Contone, gambar (RGB - biasane disimpen ing 24 bait, ing kasus kita dawa [] arrRGB = dawa anyar [256*256*256] mung njupuk 64MB ing memori), musik (amplitudo biasane digitized ing 16 utawa 24 bit. ) utawa sensor indikator diskrèt, lsp.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION