Java - تقسيم ملف نصي SQL كبير على Delimeter باستخدام الماسح الضوئي (OutOfMemoryError)

StackOverflow https://stackoverflow.com/questions/20353915

  •  25-08-2022
  •  | 
  •  

سؤال

أحاول أن أكتب تطبيقًا سيأخذ ملفًا نصيًا كبيرًا جدًا SQL ~ 60 جيجابايت (257 مليون سطر) وتقسيم كل من عبارات النسخ إلى ملفات نصية منفصلة.

ومع ذلك ، فإن الكود الذي أستخدمه حاليًا يسبب OutOfMemoryError بسبب الخطوط التي تتجاوز حد العازلة الماسحة الضوئية. البيان الأول سيكون حوالي 40 مليون خط.

public static void readFileByDelimeter(String fileName, String requestType, String output) throws FileNotFoundException {

//creating file instance
File file = new File(fileName);

//create scanner instance
Scanner scanner = new Scanner(file, "latin1");

//set custom delimeter
scanner.useDelimeter("COPY");

int number = 0;
System.out.println("Running......");
while (scanner.hasNext()){
    String line = scanner.next();
    if (line.length() > 20) {
        //save statements to seperate SQL files
        PrintWriter out = new PrintWriter("statement" + number + ".sql");
        out.println("COPY" + line.trim());
        out.close();
        }
        number++;
    }

System.out.println("Completed");
}

يرجى تقديم توصية حول ما إذا كانت هذه هي الطريقة الخاطئة لأداء هذا أو التعديلات على الطريقة الحالية.

شكرًا

هل كانت مفيدة؟

المحلول

أولاً ، لماذا تقوم بإنشاء أو بعض العمليات الأخرى هي إنشاء ملف 60 جيجابايت! ربما تحتاج إلى إلقاء نظرة على هذه العملية لإصلاح هذه العملية لإنشاء ملف نصي SQL أصغر بدلاً من إنشاء عملية جديدة. ومع ذلك ، إذا كان هذا شيءًا لمرة واحدة تحتاج إلى القيام به ، فقد يكون ذلك جيدًا ولكن لمعالجة سؤالك ، فسأستخدم Bufferreader لقراءة السجلات ومعالجتها إذا كان ملفًا كبيرًا كما أوضحت.

BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while ((line = br.readLine()) != null) {
   // process the line. and write into your output file and close the file.
   }
br.close();

نصائح أخرى

أنا شخصياً: أستخدم BufferedReader في Stead of Scanner. كما أن لديها طريقة مريحة للقراءة () ولم أواجه أي مشاكل في الأداء معها. الشيء الوحيد هو أنك ستحتاج إلى التحقق يدويًا مما إذا كانت قراءة السطر هي الخط الذي تريد معالجته ، ولكن هذا عادةً ما يكون بهذه البساطة مثل تطبيق طرق فئة السلسلة.

هذا ليس إجابة على سؤالك الفعلي ، لكنني أعتبره بديلًا سهل الاستخدام.

جرب شيئًا كهذا (ولكن أجمل):

Scanner sc = new Scanner(new BufferedReader(new FileReader(file)));

هذا يزين الأمر برمته مع قائد BufferredReader ، مما يعني أنه لن يتم تحميل كل محتوى الملف في الذاكرة في وقت واحد. يمكنك استخدام الماسح الضوئي بنفس الطريقة.

حاول استخدام عازلة Bufferreader. الاستخدام المباشر للماسح الضوئي مع ملفات الملف أو تدفقات الملفات الخام woudl قم بتحميل البيانات في الذاكرة ولن تطهيرها على GC. نهج الرهانات هو استخدام BufferedReader وقراءة سطر واحد في وقت واحد وإجراء عمليات التحقق من السلسلة اليدوية وتقسيمها. إذا تم ذلك بشكل صحيح بهذه الطريقة ، يمكنك إعطاء GC فرصة كافية لاستعادة الذاكرة عند الحاجة

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top