JavaRush /جاوا بلاگ /Random-UR /فائلوں کے ساتھ بائٹ بائٹ کام
Joysi
سطح

فائلوں کے ساتھ بائٹ بائٹ کام

گروپ میں شائع ہوا۔
کے لیے خصوصی

آو شروع کریں

سطح 18 پر، بائٹ بائی بائٹ فائل پڑھنے کے پہلے کام شروع ہوئے: فائل کو پڑھیں، پھر کم از کم/زیادہ سے زیادہ بائٹس تلاش کریں یا اسے ترتیب شدہ شکل میں آؤٹ پٹ کریں، وغیرہ۔
فائلوں کے ساتھ بائٹ بائٹ کام - 1
یہاں کے لوگ بہت ذہین ہیں۔ وہ مجموعوں کے بارے میں جانتے ہیں اور یہ کہ وہ ترتیب دے سکتے ہیں اور ڈال سکتے ہیں۔ مجموعے ایک طاقتور طریقہ کار ہیں۔ اور بہت سے لوگوں نے انہیں JavaRush سے پہلے بالکل استعمال نہیں کیا۔ یقیناً ان کا مطالعہ کرنا اور انہیں غلط جگہوں پر مارنے کی کوشش کرنا قابل ستائش ہے۔ تو آئیے ایک ایسا مسئلہ لیں جو کاموں میں نہیں ہے (تاکہ اسے حل کرتے وقت کوئی خرابی نہ ہو)، لیکن بہت ملتے جلتے ہیں:
  • کنسول سے فائل کا نام درج کریں۔
  • فائل سے تمام بائٹس پڑھیں۔
  • تکرار کو نظر انداز کرتے ہوئے، انہیں بائٹ کوڈ کے ذریعے نزولی ترتیب میں ترتیب دیں۔
  • ڈسپلے
  • 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.");
    }
}
ہر چیز کو بہت اچھا حل کرتا ہے! امتحان (اگر وہاں ہوتا تو یہ ایک دھماکے سے گزر جاتا)۔ لیکن زندگی میں کچھ فائلیں ایسی ہوتی ہیں جن میں صرف یہ لائن ہوتی ہے "ماں نے فریم دھویا۔" آئیے اپنے پروگرام کو ایک 46MB فائل فیڈ کریں (آج کے معیار کے مطابق، یہ زیادہ نہیں لگتا ہے)۔ یہ کیا ہے، پروگرام 220 سیکنڈ تک چلتا ہے۔ شام کو 1Gb فائل کو فیڈ کرنے کی کوشش (MPEG4 فلم کا سائز بہترین معیار کا نہیں ہے) ناکام رہا۔ میں ابھی بھی صبح کا پروگرام پڑھ رہا تھا - اور مجھے پہلے ہی کام پر جانا تھا۔ مسئلہ کیا ہے؟ شاید استعمال میں ہے ArrayList<Integer>جس کے اندر 1 بلین عناصر ہیں۔ اس کا ہر عنصر کم از کم 16 بائٹس لیتا ہے (ہیڈر: 8 بائٹس + فیلڈ انٹ: 4 بائٹس + ضرب 8: 4 بائٹس کے لئے سیدھ)۔ مجموعی طور پر، ہم رضاکارانہ طور پر 16 جی بی ڈیٹا میموری میں 8 کے RAM سائز کے ساتھ ڈالتے ہیں۔ ہم بہتر کریں گے۔ آئیے مجموعوں میں گہرائی میں غوطہ لگائیں۔ اور جلدی، ہمیں وہی مل گیا جس کی ہمیں ضرورت تھی۔

ٹری سیٹ سے ملو

یہ بہت کچھ ہے:
  • دو ایک جیسے عناصر کو ذخیرہ کرنے کی اجازت نہیں دیتا ہے (جس کا مطلب ہے کہ ہم ایک ارب کی بجائے تمام 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 سیکنڈ۔ 1 جی بی فائل - 3 گھنٹے 5 منٹ۔ ترقی واضح ہے۔ ہم نتائج کا "انتظار" کرنے کے قابل تھے، اور 46MB فائل پر تیزی سے کارروائی ہوتی ہے۔ آگے بڑھو. آئیے مجموعے کو ترک کرنے کی کوشش کریں (یہ کچھ لوگوں کے لیے انتہائی تکلیف دہ ہوگا)۔ ہم سادہ صفوں کا استعمال کریں گے (یہ بہت قدیم ہے)۔ آئیے ایک اہم بات نوٹ کرتے ہیں ۔ درپیش بائٹس کی تعداد کو لمبائی 256 کی ایک صف میں ڈالا جا سکتا ہے۔ لہذا ہم صرف پڑھنے والے بائٹ کے مطابق سرنی عنصر کو ایک سے بڑھا دیں گے۔

سرنی - بائٹ بائٹ

// Вариант 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 سیکنڈ۔ 1 جی بی فائل - 2 گھنٹے 55 منٹ۔ ایک بار پھر بہتری، لیکن چھوٹی۔ اور ہم نے سب کچھ آسان ٹولز سے کیا۔ ناخن چلانے کے لیے خوردبین کا استعمال نہیں کیا ۔ اب ایک شعری اختلاف۔ آئیے کمپیوٹر کی ساخت کو یاد رکھیں۔ RAM میموری (DRAM) ، جہاں پروگرام عام طور پر عمل میں آتا ہے اور متغیرات کو محفوظ کیا جاتا ہے، اس کی رسائی کی رفتار زیادہ ہوتی ہے، لیکن اس کا سائز چھوٹا ہوتا ہے۔ ہارڈ/فلیش ڈرائیو (ایچ ڈی ڈی یا فلیش ڈرائیوز) پر میموری جہاں فائلیں عام طور پر محفوظ کی جاتی ہیں، اس کے برعکس، اس کی رسائی کی رفتار کم ہے لیکن بڑا سائز ہے۔ لہذا جب ہم 1Gb فائل بائٹ بائٹ بائٹ پڑھتے ہیں (یعنی ہم HDD تک ایک ارب بار رسائی حاصل کرتے ہیں)، تو ہم ایک کم رفتار ڈیوائس کے ساتھ کام کرنے میں بہت زیادہ وقت صرف کرتے ہیں (ہم KamAZ ٹرک کے جسم سے ریت کے دانے کو دانے کے ذریعے منتقل کرتے ہیں۔ سینڈ باکس میں)۔ آئیے اسے مزید بہتر بنانے کی کوشش کرتے ہیں۔

آئیے ایک بار میں پورے کاماز ٹرک کو ریت کے ساتھ پھینک دیں!

// Вариант 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. فائل امیج ایک بائٹ سرنی ہے جس کے عناصر کی قدر -128..127 ہے۔
لہذا، بائٹس شمار کرنے کے لیے، ہم ایک ایسی تعمیر کا استعمال کریں گے arrBytes[fileImage[i] & 0b11111111]++; جو صرف سائن بٹ کو دوبارہ ترتیب دے گا اور ہمیں رینج 0..255 میں ایک قدر واپس کرے گا اور اس طرح، نتائج: 46MB فائل 0.13 سیکنڈ (ایک سیکنڈ سے کم)۔ 1 جی بی فائل - 9 سیکنڈ۔ ہم نے کر لیا! ہم ناقابل یقین حد تک ٹھنڈے ہیں! رفتار 3 گھنٹے سے 9 سیکنڈ تک۔ بس، آپ اپنی کرسی پر بیٹھ کر چائے پی سکتے ہیں۔ اور اب ایک اور تجربہ - آئیے 32 جی بی فائل آزمائیں (مثال کے طور پر ایک ایچ ڈی مووی)۔ نتیجے کے طور پر، ہمیں ونڈوز میں پروگرام کریش ہونے کے ساتھ کام کرنے والے HDD سے کریکنگ آواز آتی ہے۔ KamAZ نے جسم کو ریت کے ساتھ پھینک دیا اور سینڈ باکس کو توڑ دیا! ہم کیا کریں؟ آئیے ایک اور حقیقت یاد رکھیں۔ OS میں فائلیں عام طور پر 2-64Kb کے حصوں (کلسٹرز) میں محفوظ کی جاتی ہیں (فائل سسٹم کی قسم، سیٹنگز وغیرہ پر منحصر ہے)۔ ہم حصوں میں پڑھیں گے، مثال کے طور پر 64,000 بائٹس۔ آئیے کافی بڑے حصوں میں ایک کھدائی کے ساتھ KamAZ کو اتارنے کی کوشش کریں:

ایک بفر کا استعمال کرتے ہوئے

// Вариант 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 سیکنڈ (ایک سیکنڈ سے کم)۔ 1 جی بی فائل - 0.9 سیکنڈ (ایک سیکنڈ سے کم)۔ 32 جی بی فائل - 31 سیکنڈ۔ نوٹ کریں کہ 1 جی بی فائل کے لیے ہم نے کارکردگی کو کئی گھنٹوں سے سیکنڈوں کے حصوں تک بہتر کیا ہے !!! اس معمولی حقیقت کے ساتھ، ہم تجربہ ختم کریں گے اور ابتدائی کوڈ کو بہتر بنائیں گے۔ ہم نے بہت سے طریقوں سے ترقی کی ہے - ہم میموری کی کھپت اور آپریٹنگ ٹائم کے نئے اشارے سے خوش ہیں۔ اس کے علاوہ، اس معاملے میں، ہم معیاری لائبریری سے بیکار مجموعے نہیں نکالتے ہیں۔ PS کوئی کہے گا کہ مثال تو دور کی بات ہے وغیرہ۔ لیکن اسی طرح کے بہت سارے کام ہیں - عناصر کی ایک بڑی مقدار کا تجزیہ کرنا جن کی ریاستوں کی ایک محدود تعداد ہے۔ مثال کے طور پر، تصاویر (آر جی بی - عام طور پر 24 بائٹس میں محفوظ ہوتی ہیں، ہمارے معاملے میں لمبی[] arrRGB = new long[256*256*256] میموری میں صرف 64MB لے گی)، موسیقی (طول و عرض عام طور پر 16 یا 24 بٹس میں ڈیجیٹائز کیا جاتا ہے۔ ) یا مجرد اشارے سینسر وغیرہ۔
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION