উদ্দেশ্য-সি: লাইন দ্বারা একটি ফাইল লাইন পড়া


140

উদ্দেশ্য-সি-তে বড় টেক্সট ফাইলগুলির সাথে ডিল করার উপযুক্ত উপায় কী? ধরা যাক আমাকে প্রতিটি লাইন আলাদাভাবে পড়তে হবে এবং প্রতিটি লাইনের এনএসএসস্ট্রিং হিসাবে আচরণ করতে চাই। এটি করার সবচেয়ে কার্যকরী উপায় কী?

একটি সমাধান এনএসএসস্ট্রিং পদ্ধতি ব্যবহার করে:

+ (id)stringWithContentsOfFile:(NSString *)path 
      encoding:(NSStringEncoding)enc 
      error:(NSError **)error 

এবং তারপরে একটি নিউলাইন বিভাজক দিয়ে রেখাগুলি বিভক্ত করুন এবং তারপরে অ্যারের উপাদানগুলিতে পুনরাবৃত্তি করুন। তবে এটি মোটামুটি অদক্ষ বলে মনে হচ্ছে। ফাইলটি স্ট্রিম হিসাবে বিবেচনা করার জন্য, কেবল একবারে সমস্ত কিছু পড়ার পরিবর্তে প্রতিটি লাইনের উপরে গণনা করার কোনও সহজ উপায় নেই? জাভা এর java.io.FufferedReader মত কিন্ডা।


1
কিছুটা দেরি হয়ে গেলেও [এনএসএস স্ক্যানার স্ক্যানআপআপটোস্ট্রিং: @ "\ n" স্ট্রিং: & পড়ুন] ধরে নিন, ধরে নিচ্ছেন যে আপনি প্রতিটি পংক্তিকে 'পঠন' স্ট্রিংয়ের মধ্যে পড়তে চান।
হুনটসানিনজা

অনুরূপ এই প্রশ্নটি একবার দেখুন । আমি একটি প্রকল্প সেট আপ করেছি যা লাইন দ্বারা ফাইলগুলি লাইন পড়ার সাথে সম্পর্কিত ।
জেজেডি

উত্তর:


63

এটি একটি দুর্দান্ত প্রশ্ন। আমি মনে করি @ ডিয়েডেরিকের একটি ভাল উত্তর রয়েছে, যদিও এটি দুর্ভাগ্যজনক যে আপনারা যা করতে চান ঠিক তার জন্য কোকোর কোনও ব্যবস্থা নেই।

NSInputStreamআপনাকে এন বাইটের খণ্ডগুলি পড়ার অনুমতি দেয় (এর সাথে খুব মিল java.io.BufferedReader) তবে আপনাকে এটি NSStringনিজের হাতে রূপান্তর করতে হবে , তারপরে নিউলাইনলাইনগুলি (বা অন্য যে কোনও সীমান্তকারক) স্ক্যান করতে হবে এবং পরবর্তী পড়ার জন্য বাকী কোনও অক্ষর সংরক্ষণ করতে হবে, বা আরও অক্ষর পড়তে হবে যদি একটি নতুন লাইন এখনও পড়া হয় নি। ( NSFileHandleআপনাকে এমন একটি পড়তে দেয় NSDataযা আপনি একটিতে রূপান্তর করতে পারেন NSStringতবে এটি মূলত একই প্রক্রিয়াটি))

অ্যাপলের একটি স্ট্রিম প্রোগ্রামিং গাইড রয়েছে যা বিশদটি পূরণ করতে সহায়তা করতে পারে এবং আপনি যদি বাফারদের সাথে কাজ করছেন তবে এই এই প্রশ্নটিও আপনাকে সহায়তা করতে পারে uint8_t*

যদি আপনি প্রায়শই এই জাতীয় স্ট্রিং পড়তে যাচ্ছেন (বিশেষত আপনার প্রোগ্রামের বিভিন্ন অংশে) আপনার জন্য বিশদটি পরিচালনা করতে পারে এমন একটি শ্রেণিতে এই আচরণটি সজ্জিত করা বা সাবক্লাসিং NSInputStream(এটি নকশাকৃতভাবে নকশাকৃত করা ) ভাল ধারণা হবে সাবক্ল্যাসড ) এবং এমন পদ্ধতি যুক্ত করা যা আপনাকে যা চায় তা হ'ল পড়তে দেয়।

রেকর্ডটির জন্য, আমি মনে করি এটি যুক্ত করার জন্য একটি দুর্দান্ত বৈশিষ্ট্য হবে এবং আমি এমন কোনও কিছুর জন্য বর্ধনের অনুরোধ ফাইল করব যা এটি সম্ভব করে। :-)


সম্পাদনা: দেখা যাচ্ছে এই অনুরোধটি ইতিমধ্যে বিদ্যমান। এর জন্য ২০০ from সাল থেকে একটি রাডার ডেটিং হয়েছে (অ্যাপল অভ্যন্তরীণ লোকদের জন্য রডার: // 4742914)।


10
এই সমস্যাটি নিয়ে ডেভ ডিলংয়ের বিস্তৃত পদ্ধতিটি এখানে দেখুন: stackoverflow.com/questions/3707427#3711079
কুইন টেলর

প্লেইন এনএসডিটা এবং মেমরি ম্যাপিং ব্যবহার করাও সম্ভব। : আমি যা ডেভ ডেলং এর NSFileHandle বাস্তবায়ন হিসাবে একই এপিআই উদাহরণস্বরূপ কোড সহ একটি উত্তর তৈরি করেছেন stackoverflow.com/a/21267461/267043
Björn Olav রুড

95

এটি একটি Stringথেকে সাধারণ পড়ার জন্য কাজ করবে Text। আপনি যদি দীর্ঘতর পাঠ্য ( পাঠ্যের বৃহত আকার) পড়তে চান , তবে এখানকার অন্যান্য লোকদের যেমন বাফার করা হয়েছে (মেমরি স্পেসে পাঠ্যের আকার সংরক্ষণ করুন ) এর মতো পদ্ধতিটি ব্যবহার করুন ।

বলুন আপনি একটি পাঠ্য ফাইল পড়েছেন।

NSString* filePath = @""//file path...
NSString* fileRoot = [[NSBundle mainBundle] 
               pathForResource:filePath ofType:@"txt"];

আপনি নতুন লাইন থেকে মুক্তি পেতে চান।

// read everything from text
NSString* fileContents = 
      [NSString stringWithContentsOfFile:fileRoot 
       encoding:NSUTF8StringEncoding error:nil];

// first, separate by new line
NSArray* allLinedStrings = 
      [fileContents componentsSeparatedByCharactersInSet:
      [NSCharacterSet newlineCharacterSet]];

// then break down even further 
NSString* strsInOneLine = 
      [allLinedStrings objectAtIndex:0];

// choose whatever input identity you have decided. in this case ;
NSArray* singleStrs = 
      [currentPointString componentsSeparatedByCharactersInSet:
      [NSCharacterSet characterSetWithCharactersInString:@";"]];

ওখানে তোমার আছে।


17
আমার একটি 70 এমবি ফাইল রয়েছে, ফাইলটি পড়ার জন্য এই কোডটি ব্যবহার করা আমাকে হ্যাপ করে না এটি রৈখিকভাবে স্মৃতিশক্তি বাড়ায়। আমাকে কি কেউ সাহায্য করতে পারবেন?
গেমলয়েডিং

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

34

এই কৌতুক করতে হবে:

#include <stdio.h>

NSString *readLineAsNSString(FILE *file)
{
    char buffer[4096];

    // tune this capacity to your liking -- larger buffer sizes will be faster, but
    // use more memory
    NSMutableString *result = [NSMutableString stringWithCapacity:256];

    // Read up to 4095 non-newline characters, then read and discard the newline
    int charsRead;
    do
    {
        if(fscanf(file, "%4095[^\n]%n%*c", buffer, &charsRead) == 1)
            [result appendFormat:@"%s", buffer];
        else
            break;
    } while(charsRead == 4095);

    return result;
}

নিম্নলিখিত হিসাবে ব্যবহার করুন:

FILE *file = fopen("myfile", "r");
// check for NULL
while(!feof(file))
{
    NSString *line = readLineAsNSString(file);
    // do stuff with line; line is autoreleased, so you should NOT release it (unless you also retain it beforehand)
}
fclose(file);

এই কোডটি একবারে 4095 অবধি ফাইল থেকে অ-নিউলাইন অক্ষরগুলি পড়ে। আপনার যদি 4050 অক্ষরের চেয়ে দীর্ঘ লাইন থাকে তবে এটি কোনও নতুন লাইন বা ফাইলটির শেষের দিকে আঘাত না করে অবধি পড়া চালিয়ে যায়।

দ্রষ্টব্য : আমি এই কোডটি পরীক্ষা করিনি। এটি ব্যবহার করার আগে এটি পরীক্ষা করুন।


1
শুধু পরিবর্তন করুন [ফলাফল অ্যাপেন্ডফর্ম্যাট: "% s", বাফার]; to [ফলাফল পরিশিষ্ট ফর্ম্যাট: @ "% s", বাফার];
কোডজি

1
খালি রেখাগুলি গ্রহণের জন্য আপনি বিন্যাসটি কীভাবে পরিবর্তন করবেন, অথবা একক নিউলাইন চরিত্রের সমন্বিত লাইনগুলি কীভাবে গ্রহণ করবেন?
জাকেভ

এটি 812 লাইনের পরে আমার পক্ষে তাড়াতাড়ি থামছে। 812 তম লাইনটি "... 3 আরও", এবং এটি পাঠক আউটপুটকে খালি স্ট্রিং তৈরি করছে।
sudo

1
খালি লাইনগুলি পেরিয়ে যাওয়ার জন্য আমি একটি চেক যোগ করেছি: int fscanResult = fscanf (ফাইল, "% 4095 [^ \ n]% n% * সি", বাফার, এবং চার্স রিড) "; যদি (fscanResult == 1) {[ফলাফল অ্যাপেন্ডফর্ম্যাট: @ "% s", বাফার]; } অন্য {যদি (ফিউফ (ফাইল)) {বিরতি; if অন্যথায় যদি (ফেরার (ফাইল)! = 0) {বিরতি; sc fscanf (ফাইল, "\ n", শূন্য, এবং অক্ষর পড়ুন); বিরতি; }
রোজ-হুলম্যান

1
আমি যদি সরাসরি fscanf ডকুমেন্টেশন পড়ছি তবে "%4095[^\n]%n%*c"নিঃশব্দে প্রতিটি বাফার পড়ার সাথে একটি অক্ষর নষ্ট করে ফেলবে। দেখে মনে হচ্ছে এই ফর্ম্যাটটি বাফার দৈর্ঘ্যের চেয়ে কম হবে sh
ব্লাগো

12

Mac OS X এর ইউনিক্স হয়, উদ্দেশ্য সি, সি সুপারসেটও, তাই আপনি শুধু পুরোনো স্কুল ব্যবহার করতে পারেন fopenএবং fgetsথেকে <stdio.h>। এটি কাজ করার গ্যারান্টিযুক্ত।

[NSString stringWithUTF8String:buf]সি স্ট্রিং এ রূপান্তর করা হবে NSString। অন্যান্য এনকোডিংগুলিতে স্ট্রিং তৈরি এবং অনুলিপি ছাড়াই তৈরি করার পদ্ধতি রয়েছে।


[বেনামে অনুলিপি করা] ক্যারেক্টারটি fgetsঅন্তর্ভুক্ত করবে '\n', সুতরাং আপনি স্ট্রিংটি রূপান্তর করার আগে এটিকে সরিয়ে ফেলতে চাইতে পারেন।
কর্নেল

9

আপনি NSInputStreamফাইল স্ট্রিমগুলির জন্য একটি প্রাথমিক প্রয়োগ আছে যা ব্যবহার করতে পারেন । আপনি একটি বাফারে ( read:maxLength:পদ্ধতি) বাইটগুলি পড়তে পারেন । নিজেকে নতুন লাইনের জন্য আপনাকে বাফারটি স্ক্যান করতে হবে।


6

কোকো / অবজেক্টিভ-সি তে পাঠ্য ফাইলগুলি পড়ার উপযুক্ত উপায়টি অ্যাপলের স্ট্রিং প্রোগ্রামিং গাইডে নথিভুক্ত করা হয়েছে। ফাইলগুলি পড়ার এবং লেখার বিভাগটি আপনার পরে যা হওয়া উচিত। পিএস: একটি "লাইন" কি? "\ N" দ্বারা পৃথক একটি স্ট্রিংয়ের দুটি বিভাগ? বা "\ r"? বা "\ r \ n"? অথবা আপনি আসলে অনুচ্ছেদের পরে? পূর্বে উল্লিখিত নির্দেশিকাতে স্ট্রিংকে লাইন বা অনুচ্ছেদে বিভক্ত করার একটি অংশও অন্তর্ভুক্ত রয়েছে। (এই বিভাগটিকে "প্যারাগ্রাফ এবং লাইন ব্রেক" বলা হয়, এবং আমি উপরে উল্লিখিত পৃষ্ঠার বাম-দিকের মেনুতে লিঙ্কযুক্ত Unfortunately দুর্ভাগ্যবশত এই সাইটটি আমার হিসাবে একাধিক ইউআরএল পোস্ট করার অনুমতি দেয় না I'm এখনও বিশ্বাসযোগ্য ব্যবহারকারী নয়))

নথকে প্যারাফ্রেজ করতে: অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের মূল। সহজেই ধরে নিবেন না যে "পুরো ফাইলটি মেমরির মধ্যে পড়া" ধীর। আপনি কি বেঞ্চমার্ক করেছেন? আপনি কি জানেন যে এটি আসলে পুরো ফাইলটি মেমোরিতে পড়ে? হতে পারে এটি কেবলমাত্র একটি প্রক্সি অবজেক্ট ফেরত দেয় এবং আপনি স্ট্রিংটি গ্রাস করার সাথে সাথে পর্দার আড়ালে পড়ে থাকেন? ( অস্বীকৃতি: এনএসএসআর্টিং আসলে এটি করে কিনা আমার কোনও ধারণা নেই It এটি অনুমানযোগ্যভাবে পারে )) কথাটি হ'ল: প্রথমে ডকুমেন্টেড পদ্ধতিতে কাজগুলি করা। তারপরে, যদি মানদণ্ডগুলি দেখায় যে এটির আপনার ইচ্ছা মতো পারফরম্যান্স নেই তবে অনুকূলিত করুন।


যেহেতু আপনি সিআরএলএফ (উইন্ডোজ) লাইন শেষের কথা উল্লেখ করেছেন: এটি আসলে এমন একটি ঘটনা যা কাজগুলি করার উদ্দেশ্য-সি পথকে ভঙ্গ করে। যদি আপনি -stringWithContentsOf*অনুসরণ করা একটি পদ্ধতি ব্যবহার করেন তবে -componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]এটি পৃথকভাবে দেখবে \rএবং \nপ্রতিটি লাইনের পরে একটি ফাঁকা রেখা যুক্ত করে।
সিওভন

এটি বলেছিল, কেবলমাত্র সিআর-র ফাইলগুলিতে ফিজেটস সমাধান ব্যর্থ হয়। তবে সেগুলি আজকাল (তাত্ত্বিকভাবে) বিরল, এবং fgets এলএফ এবং সিআরএলএফ উভয়ের পক্ষে কাজ করে।
সিওভন

6

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

FILE* file = fopen("path to my file", "r");

size_t length;
char *cLine = fgetln(file,&length);

while (length>0) {
    char str[length+1];
    strncpy(str, cLine, length);
    str[length] = '\0';

    NSString *line = [NSString stringWithFormat:@"%s",str];        
    % Do what you want here.

    cLine = fgetln(file,&length);
}

নোট করুন যে ফাগেলন আপনার নতুন লাইনের চরিত্রটি রাখবে না। এছাড়াও, আমরা স্ট্রিংয়ের দৈর্ঘ্য +1 করি কারণ আমরা NULL সমাপ্তির জন্য জায়গা তৈরি করতে চাই।


4

একটি ফাইল লাইন লাইন পড়ার জন্য (চরম বড় ফাইলগুলির জন্যও) নিম্নলিখিত ফাংশনগুলি দ্বারা করা যেতে পারে:

DDFileReader * reader = [[DDFileReader alloc] initWithFilePath:pathToMyFile];
NSString * line = nil;
while ((line = [reader readLine])) {
  NSLog(@"read line: %@", line);
}
[reader release];

বা:

DDFileReader * reader = [[DDFileReader alloc] initWithFilePath:pathToMyFile];
[reader enumerateLinesUsingBlock:^(NSString * line, BOOL * stop) {
  NSLog(@"read line: %@", line);
}];
[reader release];

এটি সক্ষম করে এমন ক্লাস ডিডিফায়ারারিডারটি নিম্নলিখিত:

ইন্টারফেস ফাইল (। ঘন্টা):

@interface DDFileReader : NSObject {
    NSString * filePath;

    NSFileHandle * fileHandle;
    unsigned long long currentOffset;
    unsigned long long totalFileLength;

    NSString * lineDelimiter;
    NSUInteger chunkSize;
}

@property (nonatomic, copy) NSString * lineDelimiter;
@property (nonatomic) NSUInteger chunkSize;

- (id) initWithFilePath:(NSString *)aPath;

- (NSString *) readLine;
- (NSString *) readTrimmedLine;

#if NS_BLOCKS_AVAILABLE
- (void) enumerateLinesUsingBlock:(void(^)(NSString*, BOOL *))block;
#endif

@end

বাস্তবায়ন (। মি)

#import "DDFileReader.h"

@interface NSData (DDAdditions)

- (NSRange) rangeOfData_dd:(NSData *)dataToFind;

@end

@implementation NSData (DDAdditions)

- (NSRange) rangeOfData_dd:(NSData *)dataToFind {

    const void * bytes = [self bytes];
    NSUInteger length = [self length];

    const void * searchBytes = [dataToFind bytes];
    NSUInteger searchLength = [dataToFind length];
    NSUInteger searchIndex = 0;

    NSRange foundRange = {NSNotFound, searchLength};
    for (NSUInteger index = 0; index < length; index++) {
        if (((char *)bytes)[index] == ((char *)searchBytes)[searchIndex]) {
            //the current character matches
            if (foundRange.location == NSNotFound) {
                foundRange.location = index;
            }
            searchIndex++;
            if (searchIndex >= searchLength) { return foundRange; }
        } else {
            searchIndex = 0;
            foundRange.location = NSNotFound;
        }
    }
    return foundRange;
}

@end

@implementation DDFileReader
@synthesize lineDelimiter, chunkSize;

- (id) initWithFilePath:(NSString *)aPath {
    if (self = [super init]) {
        fileHandle = [NSFileHandle fileHandleForReadingAtPath:aPath];
        if (fileHandle == nil) {
            [self release]; return nil;
        }

        lineDelimiter = [[NSString alloc] initWithString:@"\n"];
        [fileHandle retain];
        filePath = [aPath retain];
        currentOffset = 0ULL;
        chunkSize = 10;
        [fileHandle seekToEndOfFile];
        totalFileLength = [fileHandle offsetInFile];
        //we don't need to seek back, since readLine will do that.
    }
    return self;
}

- (void) dealloc {
    [fileHandle closeFile];
    [fileHandle release], fileHandle = nil;
    [filePath release], filePath = nil;
    [lineDelimiter release], lineDelimiter = nil;
    currentOffset = 0ULL;
    [super dealloc];
}

- (NSString *) readLine {
    if (currentOffset >= totalFileLength) { return nil; }

    NSData * newLineData = [lineDelimiter dataUsingEncoding:NSUTF8StringEncoding];
    [fileHandle seekToFileOffset:currentOffset];
    NSMutableData * currentData = [[NSMutableData alloc] init];
    BOOL shouldReadMore = YES;

    NSAutoreleasePool * readPool = [[NSAutoreleasePool alloc] init];
    while (shouldReadMore) {
        if (currentOffset >= totalFileLength) { break; }
        NSData * chunk = [fileHandle readDataOfLength:chunkSize];
        NSRange newLineRange = [chunk rangeOfData_dd:newLineData];
        if (newLineRange.location != NSNotFound) {

            //include the length so we can include the delimiter in the string
            chunk = [chunk subdataWithRange:NSMakeRange(0, newLineRange.location+[newLineData length])];
            shouldReadMore = NO;
        }
        [currentData appendData:chunk];
        currentOffset += [chunk length];
    }
    [readPool release];

    NSString * line = [[NSString alloc] initWithData:currentData encoding:NSUTF8StringEncoding];
    [currentData release];
    return [line autorelease];
}

- (NSString *) readTrimmedLine {
    return [[self readLine] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

#if NS_BLOCKS_AVAILABLE
- (void) enumerateLinesUsingBlock:(void(^)(NSString*, BOOL*))block {
  NSString * line = nil;
  BOOL stop = NO;
  while (stop == NO && (line = [self readLine])) {
    block(line, &stop);
  }
}
#endif

@end

ক্লাসটি ডেভ দেলং করেছিলেন


4

ঠিক যেমন @ পার্নেল বলেছিলেন, সি এপিটি খুব সহজ।

NSString* fileRoot = [[NSBundle mainBundle] pathForResource:@"record" ofType:@"txt"];
FILE *file = fopen([fileRoot UTF8String], "r");
char buffer[256];
while (fgets(buffer, 256, file) != NULL){
    NSString* result = [NSString stringWithUTF8String:buffer];
    NSLog(@"%@",result);
}

4

অন্যরা যেমন এনএসআইপুট স্ট্রিম এবং এনএসফাইহ্যান্ডল উভয়ই উত্তর দিয়েছে ঠিক আছে তবে এটি এনএসডাটা এবং মেমরি ম্যাপিংয়ের সাথে মোটামুটি কমপ্যাক্ট পদ্ধতিতেও করা যেতে পারে:

BRLineReader.h

#import <Foundation/Foundation.h>

@interface BRLineReader : NSObject

@property (readonly, nonatomic) NSData *data;
@property (readonly, nonatomic) NSUInteger linesRead;
@property (strong, nonatomic) NSCharacterSet *lineTrimCharacters;
@property (readonly, nonatomic) NSStringEncoding stringEncoding;

- (instancetype)initWithFile:(NSString *)filePath encoding:(NSStringEncoding)encoding;
- (instancetype)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding;
- (NSString *)readLine;
- (NSString *)readTrimmedLine;
- (void)setLineSearchPosition:(NSUInteger)position;

@end

BRLineReader.m

#import "BRLineReader.h"

static unsigned char const BRLineReaderDelimiter = '\n';

@implementation BRLineReader
{
    NSRange _lastRange;
}

- (instancetype)initWithFile:(NSString *)filePath encoding:(NSStringEncoding)encoding
{
    self = [super init];
    if (self) {
        NSError *error = nil;
        _data = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedAlways error:&error];
        if (!_data) {
            NSLog(@"%@", [error localizedDescription]);
        }
        _stringEncoding = encoding;
        _lineTrimCharacters = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    }

    return self;
}

- (instancetype)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding
{
    self = [super init];
    if (self) {
        _data = data;
        _stringEncoding = encoding;
        _lineTrimCharacters = [NSCharacterSet whitespaceAndNewlineCharacterSet];
    }

    return self;
}

- (NSString *)readLine
{
    NSUInteger dataLength = [_data length];
    NSUInteger beginPos = _lastRange.location + _lastRange.length;
    NSUInteger endPos = 0;
    if (beginPos == dataLength) {
        // End of file
        return nil;
    }

    unsigned char *buffer = (unsigned char *)[_data bytes];
    for (NSUInteger i = beginPos; i < dataLength; i++) {
        endPos = i;
        if (buffer[i] == BRLineReaderDelimiter) break;
    }

    // End of line found
    _lastRange = NSMakeRange(beginPos, endPos - beginPos + 1);
    NSData *lineData = [_data subdataWithRange:_lastRange];
    NSString *line = [[NSString alloc] initWithData:lineData encoding:_stringEncoding];
    _linesRead++;

    return line;
}

- (NSString *)readTrimmedLine
{
    return [[self readLine] stringByTrimmingCharactersInSet:_lineTrimCharacters];
}

- (void)setLineSearchPosition:(NSUInteger)position
{
    _lastRange = NSMakeRange(position, 0);
    _linesRead = 0;
}

@end

1

এই উত্তরটি ObjC নয় তবে সি।

যেহেতু ওবিজেসি 'সি' ভিত্তিক, তাই কেন কল্পিত ব্যবহার করবেন না?

এবং হ্যাঁ, আমি নিশ্চিত ওবজির নিজস্ব পদ্ধতি রয়েছে - এটি কী তা আমি এখনও যথেষ্ট দক্ষ নই :)


5
আপনি যদি ওজেক্টিভ-সি-তে এটি কীভাবে করবেন তা জানেন না, তবে কেন এটি উত্তর নয়? আপনি অন্যথায় এটি করতে পারলে সোজা সি তে নেমে না যাওয়ার প্রচুর কারণ রয়েছে। উদাহরণস্বরূপ, সি ফাংশন চর * পরিচালনা করে তবে অন্য কিছু যেমন এনকোডিংগুলি পড়তে আরও অনেক বেশি কাজ লাগে। এছাড়াও, তিনি এনএসএসস্ট্রিং অবজেক্ট চান। সবাই বলেছে, এটিকে নিজেকে ঘুরিয়ে দেওয়া কেবল আরও কোড নয়, ত্রুটি-প্রবণও।
কুইন টেলর

3
আমি আপনার সাথে 100% একমত, কিন্তু আমি পেয়েছি যে (কখনও কখনও) দ্রুত উত্তর দেয় যা ভাল হয়, তা প্রয়োগ করে এবং তারপরে যখন আরও সঠিক বিকল্প প্রদর্শিত হয়, তখন এটি ব্যবহার করুন better প্রোটোটাইপ করার সময়, কাজ করার জন্য কিছু পাওয়ার সুযোগ দেওয়ার এবং সেখান থেকে অগ্রগতির ক্ষেত্রে এটি বিশেষত গুরুত্বপূর্ণ।
কেভিনডিটাইম

3
আমি কেবল বুঝতে পেরেছিলাম যে এটি "এই উত্তর" "উত্তর" নয় began ডোহ! আমি সম্মতি জানাই, মার্জিত কোডের চেয়ে কার্যকর এমন হ্যাক থাকা ভাল better আমি আপনাকে হ্রাস করি নি, তবে উদ্দেশ্য / সি কী কী তা সম্ভবত খুব সহায়ক নয়, তা জেনে একটি অনুমান ছুঁড়ে ফেলেছি। তবুও, চেষ্টা করা এমন কারও চেয়ে সর্বদা ভাল যারা জানে এবং সহায়তা করে না ... ;-)
কুইন টেলর

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

1
@ কেভিনডিটিম: আমি সম্মত; আমি কেবল দুঃখিত যে আমি এটি 5 বছরের পুরানো উত্তর ছিল না was হতে পারে এটি একটি metaপ্রশ্ন; নিয়মিত ব্যবহারকারীদের থেকে খুব পুরানো প্রশ্নগুলি কি পর্যালোচনার জন্য পতাকাঙ্কিত হতে সক্ষম হওয়া উচিত?
রোবোটিক বিড়াল

0

@ অ্যাডাম রোজেনফিল্ডের উত্তর থেকে, বিন্যাসের স্ট্রিং fscanfনীচের মত পরিবর্তন করা হবে:

"%4095[^\r\n]%n%*[\n\r]"

এটি অসক্স, লিনাক্স, উইন্ডোজ লাইন এন্ডিংয়ে কাজ করবে।


0

আমাদের জীবনকে কিছুটা সহজ করার জন্য বিভাগ বা এক্সটেনশন ব্যবহার করা Using

extension String {

    func lines() -> [String] {
        var lines = [String]()
        self.enumerateLines { (line, stop) -> () in
            lines.append(line)
        }
        return lines
    }

}

// then
for line in string.lines() {
    // do the right thing
}

0

আমি ডেভ দেলংয়ের কাছ থেকে @ লুকাসওয়েল্টের কোড এবং কোডটি পেয়েছি খুব সহায়ক। আমি এই সমস্যার সমাধান খুঁজছিলাম কিন্তু বড় ফাইলগুলি পার্স করার দরকার \r\nনেই কেবল\n

লিখিত হিসাবে কোডটিতে একাধিক অক্ষরের দ্বারা পার্সিং করা থাকলে একটি বাগ রয়েছে। আমি নীচের মত কোড পরিবর্তন করেছি।

.h ফাইল:

#import <Foundation/Foundation.h>

@interface FileChunkReader : NSObject {
    NSString * filePath;

    NSFileHandle * fileHandle;
    unsigned long long currentOffset;
    unsigned long long totalFileLength;

    NSString * lineDelimiter;
    NSUInteger chunkSize;
}

@property (nonatomic, copy) NSString * lineDelimiter;
@property (nonatomic) NSUInteger chunkSize;

- (id) initWithFilePath:(NSString *)aPath;

- (NSString *) readLine;
- (NSString *) readTrimmedLine;

#if NS_BLOCKS_AVAILABLE
- (void) enumerateLinesUsingBlock:(void(^)(NSString*, BOOL *))block;
#endif

@end

.m ফাইল:

#import "FileChunkReader.h"

@interface NSData (DDAdditions)

- (NSRange) rangeOfData_dd:(NSData *)dataToFind;

@end

@implementation NSData (DDAdditions)

- (NSRange) rangeOfData_dd:(NSData *)dataToFind {

    const void * bytes = [self bytes];
    NSUInteger length = [self length];

    const void * searchBytes = [dataToFind bytes];
    NSUInteger searchLength = [dataToFind length];
    NSUInteger searchIndex = 0;

    NSRange foundRange = {NSNotFound, searchLength};
    for (NSUInteger index = 0; index < length; index++) {
        if (((char *)bytes)[index] == ((char *)searchBytes)[searchIndex]) {
            //the current character matches
            if (foundRange.location == NSNotFound) {
                foundRange.location = index;
            }
            searchIndex++;
            if (searchIndex >= searchLength)
            {
                return foundRange;
            }
        } else {
            searchIndex = 0;
            foundRange.location = NSNotFound;
        }
    }

    if (foundRange.location != NSNotFound
        && length < foundRange.location + foundRange.length )
    {
        // if the dataToFind is partially found at the end of [self bytes],
        // then the loop above would end, and indicate the dataToFind is found
        // when it only partially was.
        foundRange.location = NSNotFound;
    }

    return foundRange;
}

@end

@implementation FileChunkReader

@synthesize lineDelimiter, chunkSize;

- (id) initWithFilePath:(NSString *)aPath {
    if (self = [super init]) {
        fileHandle = [NSFileHandle fileHandleForReadingAtPath:aPath];
        if (fileHandle == nil) {
            return nil;
        }

        lineDelimiter = @"\n";
        currentOffset = 0ULL; // ???
        chunkSize = 128;
        [fileHandle seekToEndOfFile];
        totalFileLength = [fileHandle offsetInFile];
        //we don't need to seek back, since readLine will do that.
    }
    return self;
}

- (void) dealloc {
    [fileHandle closeFile];
    currentOffset = 0ULL;

}

- (NSString *) readLine {
    if (currentOffset >= totalFileLength)
    {
        return nil;
    }

    @autoreleasepool {

        NSData * newLineData = [lineDelimiter dataUsingEncoding:NSUTF8StringEncoding];
        [fileHandle seekToFileOffset:currentOffset];
        unsigned long long originalOffset = currentOffset;
        NSMutableData *currentData = [[NSMutableData alloc] init];
        NSData *currentLine = [[NSData alloc] init];
        BOOL shouldReadMore = YES;


        while (shouldReadMore) {
            if (currentOffset >= totalFileLength)
            {
                break;
            }

            NSData * chunk = [fileHandle readDataOfLength:chunkSize];
            [currentData appendData:chunk];

            NSRange newLineRange = [currentData rangeOfData_dd:newLineData];

            if (newLineRange.location != NSNotFound) {

                currentOffset = originalOffset + newLineRange.location + newLineData.length;
                currentLine = [currentData subdataWithRange:NSMakeRange(0, newLineRange.location)];

                shouldReadMore = NO;
            }else{
                currentOffset += [chunk length];
            }
        }

        if (currentLine.length == 0 && currentData.length > 0)
        {
            currentLine = currentData;
        }

        return [[NSString alloc] initWithData:currentLine encoding:NSUTF8StringEncoding];
    }
}

- (NSString *) readTrimmedLine {
    return [[self readLine] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
}

#if NS_BLOCKS_AVAILABLE
- (void) enumerateLinesUsingBlock:(void(^)(NSString*, BOOL*))block {
    NSString * line = nil;
    BOOL stop = NO;
    while (stop == NO && (line = [self readLine])) {
        block(line, &stop);
    }
}
#endif

@end

0

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

- (NSString*)readLineFromFile:(FILE *)file
{
    char buffer[4096];
    NSMutableString *result = [NSMutableString stringWithCapacity:1000];

    int charsRead;
    do {
        if(fscanf(file, "%4095[^\r\n]%n%*[\n\r]", buffer, &charsRead) == 1) {
            [result appendFormat:@"%s", buffer];
        }
        else {
            break;
        }
    } while(charsRead == 4095);

    return result.length ? result : nil;
}

ক্রেডিট @ অ্যাডাম রোজেনফিল্ড এবং @ সুপগুলিতে যায়


0

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

enum MyError {
    case invalidTextFormat
}

extension FileHandle {

    func readLine(maxLength: Int) throws -> String {

        // Read in a string of up to the maximum length
        let offset = offsetInFile
        let data = readData(ofLength: maxLength)
        guard let string = String(data: data, encoding: .utf8) else {
            throw MyError.invalidTextFormat
        }

        // Check for carriage returns; if none, this is the whole string
        let substring: String
        if let subindex = string.firstIndex(of: "\n") {
            substring = String(string[string.startIndex ... subindex])
        } else {
            substring = string
        }

        // Wind back to the correct offset so that we don't miss any lines
        guard let dataCount = substring.data(using: .utf8, allowLossyConversion: false)?.count else {
            throw MyError.invalidTextFormat
        }
        try seek(toOffset: offset + UInt64(dataCount))
        return substring
    }

}

নোট করুন যে এটি লাইনের শেষে ক্যারেজ রিটার্ন সংরক্ষণ করে, তাই আপনার প্রয়োজনের উপর নির্ভর করে আপনি এটিকে সরাতে কোডটি সামঞ্জস্য করতে পারেন want

ব্যবহার: কেবলমাত্র আপনার টার্গেট পাঠ্য ফাইলটিতে একটি ফাইল হ্যান্ডেল খুলুন এবং readLineউপযুক্ত সর্বাধিক দৈর্ঘ্যের সাথে কল করুন - 1024 সরল পাঠ্যের জন্য মানক, তবে আপনি যদি জানেন যে এটি কম হবে। নোট করুন যে কমান্ডটি ফাইলটির শেষের দিকে প্রবাহিত হবে না, সুতরাং আপনাকে পুরোপুরি পার্স করার ইচ্ছা থাকলে আপনি নিজেই এটি পরীক্ষা করতে পারেন যে আপনি এটি পৌঁছেছেন নি। এখানে কিছু নমুনা কোড রয়েছে যা দেখায় যে কীভাবে কোনও ফাইল খুলতে myFileURLহবে এবং শেষ অবধি একে একে লাইন-লাইন পড়তে হবে।

do {
    let handle = try FileHandle(forReadingFrom: myFileURL)
    try handle.seekToEndOfFile()
    let eof = handle.offsetInFile
    try handle.seek(toFileOffset: 0)

    while handle.offsetInFile < eof {
        let line = try handle.readLine(maxLength: 1024)
        // Do something with the string here
    }
    try handle.close()
catch let error {
    print("Error reading file: \(error.localizedDescription)"
}

-2

ছোট ফাইলগুলির জন্য আমি ব্যবহার করি একটি দুর্দান্ত সহজ সমাধান:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Terrain1" ofType:@"txt"];
NSString *contents = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:nil];
NSArray *lines = [contents componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\r\n"]];
for (NSString* line in lines) {
    if (line.length) {
        NSLog(@"line: %@", line);
    }
}

তিনি একবারে একটি লাইন কীভাবে পড়বেন সে সম্পর্কে জিজ্ঞাসা করছিলেন যাতে এটি সম্পূর্ণ বিষয়বস্তুকে মেমরিতে না পড়ে read আপনার সমাধানটি পুরো বিষয়বস্তুগুলির সাথে একটি স্ট্রিং তৈরি করে তারপরে এটি লাইনে বিভক্ত হয়।
ডেভিড

-7

এই স্ক্রিপ্টটি ব্যবহার করুন, এটি দুর্দান্ত কাজ করে:

NSString *path = @"/Users/xxx/Desktop/names.txt";
NSError *error;
NSString *stringFromFileAtPath = [NSString stringWithContentsOfFile: path
                                                           encoding: NSUTF8StringEncoding
                                                              error: &error];
if (stringFromFileAtPath == nil) {
    NSLog(@"Error reading file at %@\n%@", path, [error localizedFailureReason]);
}
NSLog(@"Contents:%@", stringFromFileAtPath);

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