লাইন লাইন বড় ডেটা ফাইলগুলি কীভাবে অনুলিপি করবেন?


9

আমার কাছে 35 জিবি CSVফাইল রয়েছে। আমি প্রতিটি লাইনটি পড়তে চাই এবং লাইনটি একটি নতুন সিএসভিতে লিখতে চাই যদি এটি কোনও শর্তের সাথে মেলে।

try (BufferedWriter writer = Files.newBufferedWriter(Paths.get("source.csv"))) {
    try (BufferedReader br = Files.newBufferedReader(Paths.get("target.csv"))) {
        br.lines().parallel()
            .filter(line -> StringUtils.isNotBlank(line)) //bit more complex in real world
            .forEach(line -> {
                writer.write(line + "\n");
        });
    }
}

এটি প্রায় লাগে। 7 মিনিট। এই প্রক্রিয়াটি আরও বেশি বাড়ানো কি সম্ভব?


1
হ্যাঁ, আপনি জাভা থেকে এটি না করার চেষ্টা করতে পারেন বরং এটি সরাসরি আপনার লিনাক্স / উইন্ডোজ / ইত্যাদি থেকে করতে পারেন। অপারেটিং সিস্টেম জাভা ব্যাখ্যা করা হয়, এবং এটি ব্যবহারে সর্বদা একটি ওভারহেড থাকবে। এগুলি ছাড়াও না, আমি এটির গতি বাড়ানোর কোনও সুস্পষ্ট উপায় করি না এবং 35 গিগাবাইটের জন্য 7 মিনিট আমার পক্ষে যুক্তিসঙ্গত বলে মনে হয়।
টিম বিগলেইসেন

1
সম্ভবত parallelএটি দ্রুততর করে তোলে? এবং যে চারপাশে লাইন পরিবর্তন না?
থিলো

1
আপনি বাফার আকার সেট করতে দেয় BufferedWriterএমন কনস্ট্রাক্টর ব্যবহার করে নিজেকে তৈরি করুন । সম্ভবত একটি বড় (বা আরও ছোট) বাফার আকারটি একটি পার্থক্য আনবে। আমি BufferedWriterবাফার আকারটি হোস্ট অপারেটিং সিস্টেম বাফার আকারের সাথে মিলিয়ে দেখার চেষ্টা করব ।
আবরা

5
@ টিমবিজেলেইসেন: "জাভা ব্যাখ্যা করা হয়" সর্বোত্তমভাবে এবং প্রায় সবসময় ভুলও ভ্রান্ত হয়। হ্যাঁ, কিছু অপ্টিমাইজেশনের জন্য আপনাকে জেভিএম জগত ছেড়ে যেতে পারে, তবে জাভাতে এই দ্রুত করা অবশ্যই কার্যকর।
জোচিম সৌর

1
এমন কোনও হটস্পট রয়েছে যা সম্পর্কে আপনি কিছু করতে পারেন তা দেখার জন্য আপনার অ্যাপ্লিকেশনটি প্রোফাইল করা উচিত। আপনি কাঁচা আইও সম্পর্কে বেশি কিছু করতে পারবেন না (ডিফল্ট 8192 বাইট বাফারটি খারাপ নয়, যেহেতু সেক্টরের আকারগুলি জড়িত রয়েছে ইত্যাদি), তবে এমন কিছু ঘটতে পারে (অভ্যন্তরীণভাবে) যা আপনি সক্ষম হতে পারেন সাথে কাজ করে.
কেয়ামান

উত্তর:


4

যদি এটি কোনও বিকল্প হয় তবে আপনি ডিস্ক I / O হ্রাস করতে GZipInputStream / GZipOutputstream ব্যবহার করতে পারেন।

ফাইল.নিউবফার্ডারিডার / লেখক একটি ডিফল্ট বাফার আকার ব্যবহার করেন, 8 কেবি আমি বিশ্বাস করি। আপনি একটি বৃহত্তর বাফার চেষ্টা করতে পারেন।

স্ট্রিং, ইউনিকোডে রূপান্তর করা ধীর হয়ে যায় (এবং মেমরির দ্বিগুণ ব্যবহার করে)। ব্যবহৃত ইউটিএফ -8 স্ট্যান্ডার্ডচরেটসআইআইএসও_8859_1 এর মতো সহজ নয়।

আপনি যদি বেশিরভাগ অংশের জন্য বাইটের সাথে এবং কেবল নির্দিষ্ট সিএসভি ক্ষেত্রগুলিকে স্ট্রিংয়ে রূপান্তর করতে পারেন তবে সেরা হবে ।

একটি মেমরি ম্যাপযুক্ত ফাইলটি সবচেয়ে উপযুক্ত হতে পারে। সমান্তরালতা ফাইল ব্যাপ্তি দ্বারা ব্যবহৃত হতে পারে, ফাইল থুতু।

try (FileChannel sourceChannel = new RandomAccessFile("source.csv","r").getChannel(); ...
MappedByteBuffer buf = sourceChannel.map(...);

এটি এখন অনেকটা কোড হয়ে যাবে, লাইনগুলি এখনই পাওয়া যাচ্ছে (byte)'\n', তবে অতিরিক্ত জটিল নয়।


বাইটস পড়ার সমস্যাটি হ'ল বাস্তব বিশ্বে আমাকে লাইনের শুরুটি মূল্যায়ন করতে হবে, একটি নির্দিষ্ট চরিত্রের উপর নির্ভর করে কেবলমাত্র আউটফাইলে লাইনের অবশিষ্ট অংশটি লিখতে হয়। সুতরাং আমি সম্ভবত কেবল বাইট হিসাবে লাইনগুলি পড়তে পারি না?
membersound

আমি কেবল GZipInputStream + GZipOutputStreamএকটি র‌্যামডিস্কে সম্পূর্ণ নিখুঁতভাবে পরীক্ষা করেছি । পারফরমেন্স অনেক খারাপ ছিল ...
membersound

1
জিজিপ-তে: তবে এটি কোনও ধীর গতি নয়। হ্যাঁ, বাইটস একটি বিকল্প: নিউলাইনস, কমা, ট্যাব, সেমিকোলন সবই বাইট হিসাবে পরিচালনা করা যায়, এবং স্ট্রিংয়ের চেয়ে যথেষ্ট দ্রুত হবে। UTF-8 থেকে UTF-16 চর হিসাবে স্ট্রিং থেকে UTF-8 থেকে বাইটস।
জোপ এগজেন

1
সময়ের সাথে সাথে কেবল ফাইলের বিভিন্ন অংশ ম্যাপ করুন। আপনি যখন সীমাতে পৌঁছেছেন, কেবল MappedByteBufferসর্বশেষ জ্ঞাত-ভাল অবস্থান থেকে একটি নতুন তৈরি করুন ( FileChannel.mapলম্বা লাগে)।
জোচিম সৌর

1
2019 সালে, ব্যবহার করার দরকার নেই new RandomAccessFile(…).getChannel()। শুধু ব্যবহার FileChannel.open(…)
হলগার

0

আপনি এটি চেষ্টা করতে পারেন:

try (BufferedWriter writer = new BufferedWriter(new FileWriter(targetFile), 1024 * 1024 * 64)) {
  try (BufferedReader br = new BufferedReader(new FileReader(sourceFile), 1024 * 1024 * 64)) {

আমি মনে করি এটি আপনার এক বা দুই মিনিট সাশ্রয় করবে। বাফারের আকার নির্দিষ্ট করে প্রায় 4 মিনিটের মধ্যে আমার মেশিনে পরীক্ষা করা যেতে পারে।

এটা দ্রুত হতে পারে? এটা চেষ্টা কর:

final char[] cbuf = new char[1024 * 1024 * 128];

try (Writer writer = new FileWriter(targetFile)) {
  try (Reader br = new FileReader(sourceFile)) {
    int cnt = 0;
    while ((cnt = br.read(cbuf)) > 0) {
      // add your code to process/split the buffer into lines.
      writer.write(cbuf, 0, cnt);
    }
  }
}

এটি আপনাকে তিন বা চার মিনিট বাঁচাতে হবে।

যদি এখনও যথেষ্ট না হয়। (যে কারণে আপনি অনুমান করছেন যে প্রশ্নটি সম্ভবত আপনাকে বারবার টাস্কটি সম্পাদন করা প্রয়োজন)) যদি আপনি এটি এক মিনিট বা কয়েক সেকেন্ডের মধ্যেও করতে চান। তারপরে আপনার ডেটা প্রক্রিয়া করা উচিত এবং এটি ডিবিতে সংরক্ষণ করা উচিত, তারপরে একাধিক সার্ভার দ্বারা টাস্কটি প্রক্রিয়া করা উচিত।


আপনার শেষ উদাহরণের জন্য: আমি কীভাবে cbufবিষয়বস্তুটি মূল্যায়ন করতে পারি এবং কেবলমাত্র অংশগুলি লিখতে পারি? এবং আমি কি একবারে বাফারটি পুনরায় সেট করতে হবে? (আমি কিভাবে জানবো বাফার পূর্ণ?)
membersound

0

আপনার সমস্ত পরামর্শের জন্য ধন্যবাদ, আমি যে দ্রুততার সাথে সামনে এসেছি তা হল লেখকের সাথে বিনিময় BufferedOutputStream, যা প্রায় 25% উন্নতি দিয়েছে:

   try (BufferedReader reader = Files.newBufferedReader(Paths.get("sample.csv"))) {
        try (BufferedOutputStream writer = new BufferedOutputStream(Files.newOutputStream(Paths.get("target.csv")), 1024 * 16)) {
            reader.lines().parallel()
                    .filter(line -> StringUtils.isNotBlank(line)) //bit more complex in real world
                    .forEach(line -> {
                        writer.write((line + "\n").getBytes());
                    });
        }
    }

এখনও আমার ক্ষেত্রে BufferedReaderতুলনায় ভাল অভিনয় BufferedInputStream

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.