লাইন বাই লাইন একটি পাঠ্য ফাইল পড়ার দ্রুততম উপায় কী?


318

আমি একটি টেক্সট ফাইল লাইন লাইন পড়তে চাই। আমি জানতে চেয়েছিলাম যে আমি। নেট সি # জিনিসের সুযোগের মধ্যে যথাসম্ভব দক্ষতার সাথে এটি করছি কিনা।

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

var filestream = new System.IO.FileStream(textFilePath,
                                          System.IO.FileMode.Open,
                                          System.IO.FileAccess.Read,
                                          System.IO.FileShare.ReadWrite);
var file = new System.IO.StreamReader(filestream, System.Text.Encoding.UTF8, true, 128);

while ((lineOfText = file.ReadLine()) != null)
{
    //Do something with the lineOfText
}

7
দ্বারা Fastestআপনার কর্মক্ষমতা বা উন্নয়ন দৃষ্টিকোণ থেকে এর অর্থ কি?
SLL

1
এটি পদ্ধতির সময়কালের জন্য ফাইলটি লক করতে চলেছে। আপনি একটি অ্যারেতে ফাইল.আরেডলাইনগুলি ব্যবহার করতে পারেন তারপরে অ্যারে প্রক্রিয়াজাত করুন।
কেল

17
BTW, ঘিরা filestream = new FileStreamমধ্যে using()বিবৃতি লক ফাইল হ্যান্ডেল সম্ভব বিরক্তিকর সমস্যা এড়ানোর জন্য
SLL

ফাইল স্ট্রিম এনক্লোজিং সম্পর্কিত () স্টেটমেন্ট ব্যবহার করছে, প্রস্তাবিত পদ্ধতি সম্পর্কিত স্ট্যাকওভারফ্লো দেখুন: স্ট্যাটওভারফ্লো স্টেট স্ট্রিমডার স্টেটর স্ট্রিমডার ব্যবহার করে
ডিজি

আমি মনে করি রিডটোএন্ড () দ্রুত।
ড্যান গিফোর্ড

উত্তর:


315

লাইন দ্বারা একটি ফাইল লাইন পড়ার দ্রুততম উপায় খুঁজে পেতে আপনাকে কিছু বেঞ্চমার্কিং করতে হবে। আমি আমার কম্পিউটারে কিছু ছোট পরীক্ষা করেছি তবে আপনি আশা করতে পারবেন না যে আমার ফলাফলগুলি আপনার পরিবেশে প্রযোজ্য।

স্ট্রিমরিডার.রিডলাইন ব্যবহার করা

এটি মূলত আপনার পদ্ধতি। কোনও কারণে আপনি বাফরের আকারটিকে সবচেয়ে ছোট সম্ভাব্য মানের (128) এ সেট করেছেন। এটি বাড়ানো সাধারণভাবে কর্মক্ষমতা বাড়ায়। ডিফল্ট আকার 1,024 এবং অন্যান্য ভাল পছন্দগুলি 512 (উইন্ডোজের সেক্টর আকার) বা 4,096 (এনটিএফএসের ক্লাস্টারের আকার)। অনুকূল বাফার আকার নির্ধারণ করতে আপনাকে একটি বেঞ্চমার্ক চালাতে হবে। একটি বড় বাফার হ'ল - দ্রুত না হলে - কমপক্ষে একটি ছোট বাফারের চেয়ে ধীর না।

const Int32 BufferSize = 128;
using (var fileStream = File.OpenRead(fileName))
  using (var streamReader = new StreamReader(fileStream, Encoding.UTF8, true, BufferSize)) {
    String line;
    while ((line = streamReader.ReadLine()) != null)
      // Process line
  }

FileStreamকন্সট্রাকটর আপনাকে তা নির্দিষ্ট করার অনুমতি দেয় FileOptions । উদাহরণস্বরূপ, আপনি যদি প্রথম থেকে শেষ অবধি ধারাবাহিকভাবে একটি বড় ফাইল পড়ছেন তবে আপনি এতে উপকৃত হতে পারেন FileOptions.SequentialScan। আবার, বেঞ্চমার্কিং আপনি করতে পারেন সেরা জিনিস।

ফাইল.ইডলাইন ব্যবহার করে

এটি আপনার নিজের সমাধানের মতো খুব বেশি, ব্যতীত এটি StreamReader1,024 এর একটি নির্দিষ্ট বাফার আকার সহ ব্যবহার করে প্রয়োগ করা হয় । আমার কম্পিউটারে এটি আপনার কোডের সাথে তুলনায় 128 বাফরের আকারের তুলনায় কিছুটা ভাল পারফরম্যান্সের ফলস্বরূপ, এই পদ্ধতিটি একটি পুনরুক্তিকারী ব্লক ব্যবহার করে প্রয়োগ করা হয় এবং সমস্ত লাইনের জন্য মেমরি গ্রহণ করে না।

var lines = File.ReadLines(fileName);
foreach (var line in lines)
  // Process line

File.ReadAllLines ব্যবহার করা হচ্ছে

এটি আগের পদ্ধতির মতো অনেকটা বাদে এই পদ্ধতিটি রেখাগুলির ফিরে আসা অ্যারে তৈরি করতে ব্যবহৃত স্ট্রিংগুলির একটি তালিকা বাড়ায় যাতে মেমরির প্রয়োজনীয়তা বেশি হয়। তবে, এটি ফিরে আসে String[]এবং IEnumerable<String>এলোমেলোভাবে লাইনগুলিতে অ্যাক্সেসের অনুমতি দেয় না ।

var lines = File.ReadAllLines(fileName);
for (var i = 0; i < lines.Length; i += 1) {
  var line = lines[i];
  // Process line
}

স্ট্রিং.স্প্লিট ব্যবহার করে

এই পদ্ধতিটি কম ধীরে ধীরে ধীরে ধীরে কমপক্ষে বড় ফাইলগুলিতে (511 কেবি ফাইলে পরীক্ষা করা হয়) সম্ভবত এটি কীভাবে String.Splitবাস্তবায়িত হয়। এটি আপনার সমাধানের তুলনায় প্রয়োজনীয় মেমরিটি বাড়ানোর জন্য সমস্ত লাইনের জন্য একটি অ্যারের বরাদ্দ করে।

using (var streamReader = File.OpenText(fileName)) {
  var lines = streamReader.ReadToEnd().Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
  foreach (var line in lines)
    // Process line
}

আমার পরামর্শটি ব্যবহার করা File.ReadLinesকারণ এটি পরিষ্কার এবং দক্ষ। আপনার যদি বিশেষ ভাগ করে নেওয়ার বিকল্পের প্রয়োজন হয় (উদাহরণস্বরূপ আপনি ব্যবহার করেন FileShare.ReadWrite), আপনি নিজের কোড ব্যবহার করতে পারেন তবে আপনার বাফার আকারটি বাড়ানো উচিত।


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

আমি বুঝতে পারছি না। তাত্ত্বিকভাবে, ফাইলটি পড়তে ব্যয় করা বেশিরভাগ সময় হ'ল ডিস্কে সময় চাওয়া এবং ম্যানুপুলেটিং স্ট্রিমগুলির ওভারহেডগুলি যেমন আপনি ফাইলটির সাথে কী করবেন like রিডলাইনস। অন্যদিকে ফাইল.আরডলাইনস একসাথে মেমরির মধ্যে একটি ফাইলের সমস্ত কিছু পড়ার কথা। পারফরম্যান্সে এটি কীভাবে খারাপ হতে পারে?
h9uest

2
আমি গতির পারফরম্যান্স সম্পর্কে বলতে পারি না তবে একটি জিনিস নিশ্চিত: এটি মেমরির ব্যবহারের চেয়ে আরও খারাপ। যদি আপনাকে খুব বড় ফাইলগুলি হ্যান্ডেল করতে হয় (উদাহরণস্বরূপ জিবি), এটি খুব সমালোচনামূলক। আরও বেশি যদি এর অর্থ এটির স্মৃতি অদলবদল করতে হয়। গতির দিকে, আপনি যোগ করতে পারেন যে রিডআললাইনকে ফলস্বরূপ প্রক্রিয়া বিলম্বের আগে ফিরে আসার আগে সমস্ত লাইনগুলি পড়তে হবে। কিছু পরিস্থিতিতে গতির ইমপ্রেশনটি কাঁচা গতি বেশি গুরুত্বপূর্ণ।
বিকেকিসি

আপনি যদি বাইট অ্যারে হিসাবে স্ট্রিমটি পড়েন তবে এটি 20% ~ 80% থেকে দ্রুত পড়বে (আমি যে পরীক্ষাগুলি দিয়েছি)। আপনার যা দরকার তা হ'ল বাইট অ্যারে পাওয়া এবং এটিকে স্ট্রিংয়ে রূপান্তর করা। আমি এটি কীভাবে করেছি: পড়ার জন্য স্ট্রিম ব্যবহার করুন e পড়ুন () আপনি এটিকে কিছু অংশে পাঠানোর জন্য একটি লুপ তৈরি করতে পারেন। বাইট অ্যারেতে পুরো কন্টেন্ট সংযোজন করার পরে ( সিস্টেম.বুফার.ব্লককপি ব্যবহার করুন ) আপনাকে বাইটগুলিকে স্ট্রিংয়ে রূপান্তর করতে হবে: এনকোডিং.ডাফল্ট.গেটস্ট্রিং (বাইটকন্টেন্ট, 0, বাইটকন্টেন্ট.লেনগথ - 1) ।স্প্লিট (নতুন স্ট্রিং [ ] {"\ r \ n", "\ r", "\ n"}, স্ট্রিংস্প্লিটঅপশন.নোট);
কিম লেগে

200

আপনি যদি নেট 4 ব্যবহার করছেন তবে কেবল এটি ব্যবহার করুন File.ReadLinesযা এটি আপনার পক্ষে সব কিছু করে। আমি সন্দেহ করি এটি আপনার মতো অনেকটাই , এটি ব্যবহার করতে পারে FileOptions.SequentialScanএবং বৃহত্তর বাফার বাদে (128 খুব ছোট বলে মনে হচ্ছে)।


এর আরেকটি সুবিধা ReadLines()হ'ল এটি অলস তাই লিনক্যুতে ভাল কাজ করে।
stt106

35

যদিও File.ReadAllLines()একটি ফাইল পড়তে সহজ উপায়ে এক, এটি ধীরতম অন্যতম।

আপনি যদি খুব বেশি কিছু না করে কেবল কোনও ফাইলের লাইনগুলি পড়তে চান তবে এই মানদণ্ড অনুসারে , ফাইলটি পড়ার দ্রুততম উপায় হ'ল বয়সের পুরানো পদ্ধতি:

using (StreamReader sr = File.OpenText(fileName))
{
        string s = String.Empty;
        while ((s = sr.ReadLine()) != null)
        {
               //do minimal amount of work here
        }
}

যাইহোক, যদি আপনাকে প্রতিটি লাইনের সাথে অনেক কিছু করতে হয়, তবে এই নিবন্ধটি উপসংহারে পৌঁছেছে যে সর্বোত্তম উপায়টি নিম্নলিখিতটি (এবং কোনও স্ট্রিং প্রাক-বরাদ্দকরণে দ্রুততর [] যদি আপনি জানেন যে আপনি কতগুলি লাইন পড়তে চলেছেন):

AllLines = new string[MAX]; //only allocate memory here

using (StreamReader sr = File.OpenText(fileName))
{
        int x = 0;
        while (!sr.EndOfStream)
        {
               AllLines[x] = sr.ReadLine();
               x += 1;
        }
} //Finished. Close the file

//Now parallel process each line in the file
Parallel.For(0, AllLines.Length, x =>
{
    DoYourStuff(AllLines[x]); //do your work here
});

13

নিম্নলিখিত কোড ব্যবহার করুন:

foreach (string line in File.ReadAllLines(fileName))

এটি পড়ার পারফরম্যান্সের মধ্যে একটি বিশাল পার্থক্য ছিল।

এটি মেমরির খরচ ব্যয় করে আসে তবে এটি সম্পূর্ণ মূল্যবান!


আমি পছন্দ করবো File.ReadLines (আমি ক্লিক করুন) চেয়েFile.ReadAllLines
newbieguy

5

স্ট্যাক ওভারফ্লো প্রশ্নে এটি সম্পর্কে একটি ভাল বিষয় রয়েছে 'পুরানো স্কুল "রিটার্নের চেয়ে' ফলন ফেরত 'ধীর?

এটা বলে:

রিডআললাইনস সমস্ত লাইন মেমরিতে লোড করে এবং একটি স্ট্রিং প্রদান করে []। ফাইলটি ছোট হলে সমস্ত ভাল এবং ভাল। যদি ফাইলটি মেমরির সাথে ফিট করে তার চেয়ে বড় হয় তবে আপনার মেমরি চলে যাবে।

অন্যদিকে রিডলাইনস একবারে এক লাইনে ফিরতে ফলন ফিরতি ব্যবহার করে। এটির সাহায্যে আপনি যে কোনও আকারের ফাইল পড়তে পারেন। এটি পুরো ফাইলটিকে মেমরিতে লোড করে না।

বলুন যে আপনি প্রথম লাইনটি খুঁজে পেতে চেয়েছিলেন যাতে "foo" শব্দটি রয়েছে এবং তারপরে প্রস্থান করতে পারেন। রিডএললাইনগুলি ব্যবহার করে, আপনাকে প্রথম ফাইলটি মেমোরিতে পড়তে হবে, এমনকি যদি প্রথম লাইনে "foo" দেখা দেয়। রিডলাইনগুলির সাহায্যে আপনি কেবল একটি লাইন পড়েন। কোনটি দ্রুত হবে?


4

যদি ফাইলের আকারটি বড় না হয় তবে পুরো ফাইলটি পড়া এবং পরে এটি ভাগ করে নেওয়া আরও দ্রুত

var filestreams = sr.ReadToEnd().Split(Environment.NewLine, 
                              StringSplitOptions.RemoveEmptyEntries);

6
File.ReadAllLines()
jgauffin

@ জাগাফিন আমি ফাইলটি প্রয়োগের পিছনে চিনি না eআডলাইনলাইনস () তবে আমি মনে করি এটির একটি সীমিত বাফার রয়েছে এবং ফাইলআরএডটিঅ্যান্ড বাফারটি আরও বেশি হওয়া উচিত, সুতরাং এইভাবে ফাইলের অ্যাক্সেসের সংখ্যা হ্রাস পাবে এবং স্ট্রিংয়ের মাধ্যমে স্প্লিট করুন p কেস ফাইলের আকার বড় নয় ফাইলের একাধিক অ্যাক্সেসের চেয়ে দ্রুত।
সা Saeedদ আমিরি

আমি সন্দেহ করি যে File.ReadAllLinesফাইল আকারটি পরিচিত হওয়ার পরে থেকে একটি নির্দিষ্ট বাফার আকার রয়েছে।
jgauffin

1
@ জাগাফিন: ইন। নেট 4.0.০ File.ReadAllLinesএকটি তালিকা তৈরি করে এবং একটি লুপে StreamReader.ReadLine(অন্তর্নিহিত অ্যারের সম্ভাব্য পুনঃব্যবস্থা সহ) ব্যবহার করে এই তালিকায় যুক্ত করে । এই পদ্ধতিটি 1024 এর একটি ডিফল্ট বাফার আকার ব্যবহার করে The StreamReader.ReadToEndলাইন পার্সিং অংশটিকে এড়িয়ে যায় এবং পছন্দসই হলে বাফার আকারটি কনস্ট্রাক্টরে সেট করা যায়।
মার্টিন লিভারেজ

ফাইল আকারের ক্ষেত্রে "বিগ" সংজ্ঞায়িত করা সহায়ক হবে।
পল

2

আপনার যদি পর্যাপ্ত স্মৃতি থাকে তবে আমি পুরো ফাইলটিকে একটি মেমরি স্ট্রিমে পড়ে এবং তারপরে লাইনগুলি পড়ার জন্য একটি স্ট্রিম রিডার খোলার মাধ্যমে কিছু কর্মক্ষমতা অর্জন করেছি । যতক্ষণ না আপনি যতক্ষণ না পুরো ফাইলটি পড়ার পরিকল্পনা করছেন, এটি কিছু উন্নতি করতে পারে।


1
File.ReadAllLinesতখন আরও ভাল পছন্দ বলে মনে হচ্ছে।
jgauffin

2

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

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