JavaRush /جاوا بلاگ /Random-SD /بائيٽ بائيٽ فائلن سان ڪم
Joysi
سطح

بائيٽ بائيٽ فائلن سان ڪم

گروپ ۾ شايع ٿيل
لاء خاص

اچو ته شروع ڪريون

سطح 18 تي، بائيٽ بائيٽ فائل پڙهڻ جا پھريون ڪم شروع ٿيا: فائل کي پڙھو، پوءِ گھٽ ۾ گھٽ / وڌ ۾ وڌ بائيٽ ڳولھيو يا ان کي آرڊر ٿيل فارم ۾ ٻاھر ڪڍو، وغيره.
فائلن سان بائيٽ بائيٽ ڪم - 1
هتي جا ماڻهو ڏاڍا ذهين آهن. اهي مجموعن جي باري ۾ ڄاڻن ٿا ۽ اهي ترتيب ۽ داخل ڪري سگهن ٿا. مجموعا هڪ طاقتور ميکانيزم آهن. ۽ ڪيترن ئي جاوا رش کان اڳ انهن کي استعمال نه ڪيو. يقينن، انهن جو مطالعو ڪرڻ ۽ انهن کي غلط هنڌن تي مارڻ جي ڪوشش ڪرڻ قابل تعريف آهي. سو. اچو ته هڪ مسئلو وٺون جيڪو ڪمن ۾ نه آهي (انهي ڪري ته ان کي حل ڪرڻ وقت ڪو به خراب ڪندڙ نه آهن)، پر اتي تمام گهڻيون آهن:
  • ڪنسول مان فائل جو نالو داخل ڪريو
  • فائل مان سڀئي بائيٽ پڙهو.
  • ورهاڱي کي نظر انداز ڪندي، انهن کي ترتيب ڏيو بائيٽ ڪوڊ جي ترتيب سان.
  • ڏيکاريو
  • بند ڪريو I/O وهڪرو
ان پٽ فائل جو مثال بائيٽ 44 83 44 آئوٽ پُٽ جو مثال 83 44 اسان اضافي طور تي متعارف ڪرايا ويريبلز startTime۽ finishTimeپروگرام جي عمل جي وقت کي رڪارڊ ڪرڻ لاءِ. حساب ڪتاب لاءِ مون استعمال ڪيو i3-3GHz/8Gb RAM/HDD WD Blue-1Tb/Win7-64/jdk-8u73-windows-x64 (اختيارن 1-2 ۾ پروگرامن جا مثال info.javarush فورم تان ورتا ويا آهن، اهي ٿورا آهن تبديل ٿيل صرف ترتيب ڏيڻ لاءِ چڙهڻ واري ترتيب ۾ ٺيڪ آهي - يعني اهي حقيقي آهن!!)

اچو ته ان کي سر تي حل ڪريون:

// Вариант 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.");
    }
}
تمام سٺو حل ڪري ٿو! امتحان (جيڪڏهن اتي هجي ها ته اهو هڪ ڌڪ سان پاس ٿئي ها). پر زندگي ۾ ڪجھ فائلون آھن جن ۾ صرف لڪير شامل آھي "ماء فريم کي ڌوئي." اچو ته اسان جي پروگرام کي 46 ايم بي فائل ڏيون (اڄ جي معيار موجب، اهو گهڻو ڪجهه نٿو لڳي). اهو ڇا آهي، پروگرام 220 سيڪنڊن لاء هلندو آهي. شام جو هڪ 1Gb فائل کي فيڊ ڪرڻ جي ڪوشش (MPEG4 فلم جي سائيز بهترين معيار جي ناهي) ناڪام ٿي وئي. مان اڃا صبح جو پروگرام پڙهي رهيو هوس - ۽ مون کي اڳ ۾ ئي ڪم تي وڃڻو هو. ڇا مسئلو آهي؟ شايد استعمال ۾ آهي ArrayList<Integer>جنهن جي اندر 1 بلين عناصر آهن. ان جو هر عنصر گھٽ ۾ گھٽ 16 بائيٽ وٺي ٿو (هيڊر: 8 بائيٽ + فيلڊ انٽ: 4 بائيٽ + ضرب جي لاءِ ترتيب 8: 4 بائيٽ). مجموعي طور تي، اسان رضاڪارانه طور تي 16 Gb ڊيٽا ميموري ۾ 8 جي ريم سائيز سان رکون ٿا. اسان بهتر ڪنداسين. اچو ته مجموعن ۾ وڌيڪ اونهي وڃو. ۽ جلدي، اسان کي مليو جيڪو اسان کي گهربل آهي.

TreeSet سان ملو

هي تمام گهڻو آهي:
  • ٻن هڪجهڙا عنصرن کي ذخيرو ڪرڻ جي اجازت نه ٿو ڏئي (جنهن جو مطلب آهي ته اسان سڀني 255 عناصر کي ياداشت ۾ ذخيرو ڪنداسين، هڪ بلين جي بدران!)
  • جڏهن ان جي عناصر کي هٿي وٺندي، اهو خودڪار طريقي سان ترتيب ڏئي ٿو (پنهنجو پاڻ کي ترتيب ڏئي ٿو - هتي اهو آهي، تڪميل جي اونچائي!)
اسان حاصل ڪريون ٿا:
// Вариант 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.");
    }
}
ٻاھر آھي: 46MB فائل، 176 سيڪنڊ. 1Gb فائل - 3 ڪلاڪ 5 منٽ. ترقي پڌري آهي. اسان نتيجن لاء "انتظار" ڪرڻ جي قابل ٿي ويا، ۽ 46MB فائل تي عمل ڪيو ويو تيزيء سان. اڳتي وڃو. اچو ته مجموعا ڇڏڻ جي ڪوشش ڪريو (اهو ڪجهه لاء انتهائي دردناڪ ٿيندو). اسان استعمال ڪنداسين سادو صفون (اهو ايترو پرائمٽ آهي). اچو ته هڪ اهم ڳالهه نوٽ ڪريون . سامهون آيل بائيٽن جو تعداد 256 جي ڊگھائي جي صف ۾ رکي سگھجي ٿو. ان ڪري اسان صرف پڙھندڙ ​​بائيٽ سان ملندڙ صف جي عنصر کي ھڪڙي وڌائينداسين.

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.");
    }
}
ٻاھر آھي: 46MB فائل، 158 سيڪنڊ. 1Gb فائل - 2 ڪلاڪ 55 منٽ. ٻيهر هڪ بهتري، پر ننڍڙو. ۽ اسان سڀ ڪجھ سادي اوزار سان ڪيو. ڊرائيونگ ناخن لاء خوردبيني استعمال نه ڪيو . هاڻي هڪ شعري بحث. اچو ته ڪمپيوٽر جي جوڙجڪ کي ياد رکون. RAM ياداشت (DRAM) ، جتي پروگرام عام طور تي عمل ڪيو ويندو آهي ۽ متغير ذخيرو ٿيل آهن، هڪ اعلي رسائي جي رفتار آهي، پر سائيز ۾ ننڍو آهي. هارڊ/فليش ڊرائيو (HDD يا فليش ڊرائيو) تي ميموري جتي فائلون عام طور تي محفوظ ڪيون وينديون آهن، ان جي برعڪس، ان جي پهچ جي رفتار گهٽ هوندي آهي پر وڏي سائيز. تنهن ڪري جڏهن اسان هڪ 1Gb فائل بائيٽ بائيٽ پڙهون ٿا (يعني اسان هڪ بلين ڀيرا HDD تائين رسائي ڪريون ٿا)، اسان تمام گهڻو وقت گذاريون ٿا هڪ گهٽ رفتار واري ڊوائيس سان ڪم ڪرڻ (اسان ڪماز ٽرڪ جي جسم مان اناج ذريعي اناج کي منتقل ڪريون ٿا. سينڊ باڪس ۾). اچو ته ان کي وڌيڪ بهتر ڪرڻ جي ڪوشش ڪريون.

اچو ته سڄي ڪاماز ٽرڪ کي ريٽي سان گڏ هڪ ئي وقت ٻاهر ڪڍون!

// Вариант 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.");
    }
}
هڪ ننڍڙو، پر ٻيهر اهم تڪرار . نوٽ:
  1. arrBytes انڊيڪس 0..255 اندر بيان ڪيو ويو آهي،
  2. fileImage هڪ بائيٽ صف آهي جنهن جي عناصرن جي قيمت آهي -128..127
تنهن ڪري، بائيٽ ڳڻڻ لاءِ، اسان هڪ تعمير استعمال ڪنداسين arrBytes[fileImage[i] & 0b11111111]++; جيڪو صرف سائن بٽ کي ري سيٽ ڪندو ۽ اسان کي رينج 0..255 ۾ هڪ قدر واپس ڪندو ۽ پوءِ، نتيجا: 46MB فائل 0.13 سيڪنڊ (هڪ سيڪنڊ کان گهٽ). 1 جي بي فائل - 9 سيڪنڊ. اسان ڪيو! اسان ناقابل يقين حد تائين ٿڌو آهيون! رفتار 3 ڪلاڪ کان 9 سيڪنڊن تائين. اهو ئي آهي، توهان واپس پنهنجي ڪرسيء تي ويهي سگهو ٿا ۽ ڪجهه چانهه پيئي سگهو ٿا. ۽ هاڻي هڪ ٻيو تجربو - اچو ته 32 Gb فائل جي ڪوشش ڪريو (مثال طور، هڪ HD فلم). نتيجي طور، اسان کي ونڊوز ۾ حادثو ٿيڻ واري پروگرام سان ڪم ڪندڙ HDD مان هڪ ٻرندڙ آواز ملي ٿو. KamAZ لاش کي ريل سان اڇلائي ڇڏيو ۽ سينڊ باڪس کي ٽوڙي ڇڏيو! اسان ڇا ڪريون؟ اچو ته هڪ ٻي حقيقت ياد ڪريون. OS ۾ فائلون عام طور تي 2-64Kb جي حصن (ڪلسٽرز) ۾ ذخيرو ٿيل آهن (انحصار فائل سسٽم جي قسم تي، سيٽنگون، وغيره). اسان حصن ۾ پڙهنداسين، مثال طور 64,000 بائيٽ. اچو ته ڪوشش ڪريون ته ڪاماز کي ان لوڊ ڪرڻ جي ڪوشش ڪريون هڪ excavator سان ڪافي وڏي حصن ۾:

بفر استعمال ڪندي

// Вариант 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.");
    }
}
نتيجي طور، اسان حاصل ڪيو: 46MB فائل 0.08 سيڪنڊ (هڪ سيڪنڊ کان گهٽ). 1Gb فائل - 0.9 سيڪنڊ (هڪ سيڪنڊ کان گھٽ). 32Gb فائل - 31 سيڪنڊ. نوٽ ڪريو ته هڪ 1 Gb فائل لاءِ اسان ڪارڪردگي بهتر ڪئي آهي ڪيترن ئي ڪلاڪن کان سيڪنڊن جي حصن تائين !!! هن معمولي حقيقت سان، اسان تجربو ختم ڪنداسين ۽ شروعاتي ڪوڊ کي بهتر بڻائينداسين. اسان ڪيترن ئي طريقن سان ترقي ڪئي آهي - اسان ميموري جي استعمال ۽ آپريٽنگ وقت جي نئين اشارن سان خوش آهيون. انهي سان گڏ، هن معاملي ۾، اسان معياري لائبريري مان بيڪار مجموعا نه ڪڍندا آهيون. PS ڪو چوندو ته مثال تمام گهڻو آهي، وغيره. پر اتي تمام گھڻا ساڳيا ڪم آھن - عناصر جي ھڪڙي وڏي مقدار جو تجزيو ڪرڻ لاءِ جن وٽ رياستن جو محدود تعداد آھي. مثال طور، تصويرون (آر جي بي - عام طور تي 24 بائيٽس ۾ ذخيرو ٿيل، اسان جي صورت ۾ ڊگهو[] آر آر آر جي بي = نئون ڊگهو[256*256*256] صرف 64 ايم بي ميموري ۾ وٺندو)، موسيقي (تعداد عام طور تي 16 يا 24 بٽ ۾ ڊجيٽل ٿيل آهي. ) يا جدا جدا اشارن سينسر، وغيره.
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION