একটি পাঠ্য ফাইলের মধ্যে রেখার সংখ্যা নির্ধারণ করুন


209

কোনও পাঠ্য ফাইলের মধ্যে লাইন সংখ্যা প্রোগ্রামক্রমে নির্ধারণ করার জন্য কি সহজ উপায় আছে?

উত্তর:


396

গুরুতরভাবে বেল্ট সম্পাদনা: আপনি। নেট 4.0 বা তার পরে ব্যবহার করছেন

Fileবর্গ একটি নতুন হয়েছে ReadLinesপদ্ধতি যা প্রখর রৌদ্রে সাগ্রহে তাদের সবাইকে মত একটি অ্যারের মধ্যে পড়া বদলে লাইন উল্লেখ ReadAllLines। সুতরাং এখন আপনার সাথে দক্ষতা এবং সংক্ষিপ্ততা উভয়ই থাকতে পারে:

var lineCount = File.ReadLines(@"C:\file.txt").Count();

আসল উত্তর

আপনি যদি দক্ষতার বিষয়ে খুব বেশি বিরক্ত না হন তবে আপনি কেবল লিখতে পারেন:

var lineCount = File.ReadAllLines(@"C:\file.txt").Length;

আরও কার্যকর পদ্ধতির জন্য আপনি এটি করতে পারেন:

var lineCount = 0;
using (var reader = File.OpenText(@"C:\file.txt"))
{
    while (reader.ReadLine() != null)
    {
        lineCount++;
    }
}

সম্পাদনা: দক্ষতা সম্পর্কে প্রশ্নের জবাবে

দ্বিতীয়টি যেহেতু আমি বেশি দক্ষ বলেছিলাম তা স্মরণে ব্যবহারের বিষয়ে ছিল, অগত্যা গতি নয়। প্রথমটি ফাইলের সম্পূর্ণ সামগ্রী একটি অ্যারেতে লোড করে যার অর্থ এটি অবশ্যই ফাইলের আকার হিসাবে কমপক্ষে মেমরি বরাদ্দ করতে হবে। দ্বিতীয়টি কেবল একবারে একটি লাইন লুপ করে তাই এটি একবারে এক লাইনের বেশি মেমরির বরাদ্দ করতে হয় না। এটি ছোট ফাইলগুলির পক্ষে তেমন গুরুত্বপূর্ণ নয়, তবে বড় ফাইলগুলির জন্য এটি একটি সমস্যা হতে পারে (আপনি যদি চেষ্টা করে 32b-বিট সিস্টেমে 4GB ফাইলে লাইন সংখ্যাটি খুঁজে বের করেন, উদাহরণস্বরূপ, যেখানে কেবল পর্যাপ্ত পরিমাণ নেই) ব্যবহারকারী-মোড ঠিকানার স্থানটি এটিকে বড় পরিমাণে বরাদ্দ করতে)।

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


2
ছোট নোট: স্ট্রিং একটি রেফারেন্স টাইপ হওয়ায় অ্যারেটি একটি পয়েন্টারের আকার x রেখার সংখ্যার আকার হতে পারে তবে আপনি সঠিক যে এটি প্রতিটি স্ট্রিং অবজেক্ট হিসাবে প্রতিটি লাইন পাঠ্য সংরক্ষণ করতে হবে।
মাইক ডিমমিক

16
এফওয়াইআই: করার জন্য আপনাকে আপনার অন্তর্ভুক্তগুলিতে ReadLines().Count()একটি যুক্ত করতে হবে using System.Linq। এই সংযোজনটির প্রয়োজন মনে হয়েছে এটি মোটামুটি স্বজ্ঞাত নয়, তাই আমি এটি উল্লেখ করছি mention আপনি যদি ভিজুয়াল স্টুডিও ব্যবহার করছেন তবে সম্ভবত এটি সংযোজন স্বয়ংক্রিয়ভাবে হয়ে গেছে।
নিউক্লিওন

2
আমি উভয় পন্থা পরীক্ষা করেছি, "ফাইল.আরডলাইনস.কাউন্ট ()" ভি / এস "রিডার। রিডলাইন ()" এবং "রিডার। রিডলাইন ()" কিছুটা দ্রুত তবে এটি খুব সামান্য ব্যবধানের সাথে দ্রুত। "রিডএললাইনস" লঘার যা দ্বিগুণ সময় নেয় এবং প্রচুর স্মৃতি খায়)। এটি কারণ "ফাইল.আরডলাইনস.কাউন্ট ()" এবং "রিডার। রিডলাইন ()" এমন একটি গণক যা ফাইলটি লাইন দিয়ে পঠন করে এবং পুরো ফাইলটিকে মেমরিতে লোড করে না এবং এটি আবার র‌্যামে পড়ে না।
যোগি

9
হ্যাঁ, 4GB + ফাইলের সাথে কেউ কখনও কাজ করে না। আমরা অবশ্যই কখনও বৃহত লগ ফাইলগুলির সাথে ডিল করি না। অপেক্ষা কর.
গ্রেগ বিচ

2
আপনি যদি ফাইলের অভ্যন্তরীণ অংশ দেখতে চান e রিডলাইনস () এখানে যান: System.IO.File.cs আপনি যখন ওভারলোডগুলির মাধ্যমে ড্রিল করেন তখন এটি আপনাকে এখানে নিয়ে যায়: রিডলাইনসআইট্রেটার.সি
স্টিভ কিনিয়ন


8

এটি কম স্মৃতি ব্যবহার করবে তবে সম্ভবত আরও বেশি সময় লাগবে

int count = 0;
string line;
TextReader reader = new StreamReader("file.txt");
while ((line = reader.ReadLine()) != null)
{
  count++;
}
reader.Close();

5

যদি সহজেই আপনি বোঝাতে চান কোডের একটি লাইন বোঝা সহজ তবে প্রতি সুযোগে অক্ষম?

string[] lines = System.IO.File.RealAllLines($filename);
int cnt = lines.Count();

এটি সম্ভবত কতটি লাইনের দ্রুততম উপায়।

আপনি এটিও করতে পারেন (আপনি যদি এটিতে বাফার করছেন তবে তার উপর নির্ভর করে)

#for large files
while (...reads into buffer){
string[] lines = Regex.Split(buffer,System.Enviorment.NewLine);
}

অন্যান্য অসংখ্য উপায় রয়েছে তবে উপরের একটি সম্ভবত আপনি যা করতে যাচ্ছেন।


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

2

আপনি এটি দ্রুত পড়তে এবং একটি পাল্টা বাড়িয়ে দিতে পারেন, কেবলমাত্র ইনক্রিমেন্টের জন্য একটি লুপ ব্যবহার করুন, পাঠ্যটি দিয়ে কিছুই না করে।


3
এটি একটি মন্তব্য হওয়া উচিত, উত্তর নয়।
IamBatman

2

কোনও ফাইল পড়লে এবং নিজেই কিছুটা সময় নেয়, ফলাফল সংগ্রহ করা আবর্জনা আরেকটি সমস্যা কারণ আপনি কেবলমাত্র নতুন লাইনের চরিত্র (গুলি) গণনা করার জন্য পুরো ফাইলটি পড়েন,

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

নিম আরা একটি দুর্দান্ত বিশ্লেষণ করেছেন যা আপনি বিবেচনায় নিতে পারেন

প্রস্তাবিত সমাধানটি এখানে দেওয়া হয়েছে, যেহেতু এটি একবারে 4 টি অক্ষর পড়ে, লাইন ফিডের চরিত্রটিকে গণনা করে এবং পরবর্তী অক্ষরের তুলনায় আবার একই মেমরি ঠিকানাটি পুনরায় ব্যবহার করে।

private const char CR = '\r';  
private const char LF = '\n';  
private const char NULL = (char)0;

public static long CountLinesMaybe(Stream stream)  
{
    Ensure.NotNull(stream, nameof(stream));

    var lineCount = 0L;

    var byteBuffer = new byte[1024 * 1024];
    const int BytesAtTheTime = 4;
    var detectedEOL = NULL;
    var currentChar = NULL;

    int bytesRead;
    while ((bytesRead = stream.Read(byteBuffer, 0, byteBuffer.Length)) > 0)
    {
        var i = 0;
        for (; i <= bytesRead - BytesAtTheTime; i += BytesAtTheTime)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 1];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 2];
                if (currentChar == detectedEOL) { lineCount++; }

                currentChar = (char)byteBuffer[i + 3];
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
                i -= BytesAtTheTime - 1;
            }
        }

        for (; i < bytesRead; i++)
        {
            currentChar = (char)byteBuffer[i];

            if (detectedEOL != NULL)
            {
                if (currentChar == detectedEOL) { lineCount++; }
            }
            else
            {
                if (currentChar == LF || currentChar == CR)
                {
                    detectedEOL = currentChar;
                    lineCount++;
                }
            }
        }
    }

    if (currentChar != LF && currentChar != CR && currentChar != NULL)
    {
        lineCount++;
    }
    return lineCount;
}

উপরে আপনি দেখতে পাচ্ছেন যে লাইনটি একবারে একটি অক্ষর পড়ার পাশাপাশি অন্তর্নিহিত কাঠামো দ্বারা পড়তে হবে কারণ আপনাকে লাইন ফিডটি দেখতে সমস্ত অক্ষর পড়তে হবে।

আপনি যদি এটি সম্পন্ন উপ-নিম হিসাবে প্রোফাইল করেন তবে আপনি দেখতে পাবেন এটি এটি করার একটি বরং দ্রুত এবং দক্ষ উপায়।


1

গাড়ীর রিটার্ন / লাইন ফিড গণনা করুন। আমি ইউনিকোডে বিশ্বাস করি তারা যথাক্রমে 0x000D এবং 0x000A। আপনি চান হিসাবে আপনি যেভাবে দক্ষ বা অদক্ষ হতে পারে এবং আপনি উভয় চরিত্রের সাথে ডিল করতে হবে কিনা তা সিদ্ধান্ত নিতে পারেন


1

একটি ব্যবহারযোগ্য বিকল্প, এবং একটি যা আমি ব্যক্তিগতভাবে ব্যবহার করেছি, তা হ'ল ফাইলটির প্রথম লাইনে আপনার নিজের শিরোনাম যুক্ত করা। আমি আমার গেমের জন্য একটি কাস্টম মডেল বিন্যাসের জন্য এটি করেছি। মূলত, আমার কাছে একটি সরঞ্জাম রয়েছে যা আমার .obj ফাইলগুলিকে অনুকূল করে, আমার যে ক্র্যাপগুলি দরকার নেই তা থেকে মুক্তি পেয়ে এগুলি একটি ভাল বিন্যাসে রূপান্তরিত করে, এবং তারপরে লাইন, মুখ, নরমালস, শীর্ষগুলি এবং টেক্সচার ইউভিগুলিতে মোট সংখ্যা লিখে যায়। প্রথম লাইন মডেলটি লোড হওয়ার পরে সেই তথ্যটি বিভিন্ন অ্যারে বাফার দ্বারা ব্যবহৃত হয়।

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


-1
try {
    string path = args[0];
    FileStream fh = new FileStream(path, FileMode.Open, FileAccess.Read);
    int i;
    string s = "";
    while ((i = fh.ReadByte()) != -1)
        s = s + (char)i;

    //its for reading number of paragraphs
    int count = 0;
    for (int j = 0; j < s.Length - 1; j++) {
            if (s.Substring(j, 1) == "\n")
                count++;
    }

    Console.WriteLine("The total searches were :" + count);

    fh.Close();

} catch(Exception ex) {
    Console.WriteLine(ex.Message);
}         

5
-1: এটি স্বল্প হবে, প্রচুর স্মৃতি গ্রহণ করবে এবং জিসিকে হার্ড সময় দেবে!
ya23

-2

আপনি "চালু করতে পারে wc- .exe" এক্সিকিউটেবল (দিয়ে আসে UnixUtils একটি বহিস্থিত প্রক্রিয়া হিসেবে এবং ইনস্টলেশন প্রয়োজন নেই) রান। এটি বিভিন্ন লাইন গণনা পদ্ধতি সমর্থন করে (যেমন ইউনিক্স বনাম ম্যাক বনাম উইন্ডো))


1
এটি কার্যকর হওয়ার পক্ষে যথেষ্ট দ্রুত কোনও উপায় নেই। কেবল এক্সিকিউটেবল কল করার ওভারহেড একক ইনক্রিমেন্টিং লুপের চেয়ে দ্বিগুণ (স্পষ্টত অতিরঞ্জিত স্পষ্ট) would
Krythic
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.