打开文件并从文件中读取 Objective-C

7

我正在尝试打开一个文件,并从中读取内容,但是遇到了一些问题。

FILE *libFile = fopen("/Users/pineapple/Desktop/finalproj/test242.txt","r");
char wah[200];
fgets(wah, 200, libFile);
printf("%s test\n", wah);

这将打印出:\377\376N test,而不是我的文件内容中的任何内容。

有任何想法吗?

完整代码:

#import <Cocoa/Cocoa.h>
#import <stdio.h>

int main(int argc, char *argv[])
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

FILE *libFile = fopen("/Users/pineapple/Desktop/finalproj/test242.txt","r");
if(libFile){
char wah[200];
fgets(wah, 200, libFile);
printf("%s test\n", wah);
    }
[pool drain];
return 0;

}

并且test242.txt文件的字符数不能超过200个。

6个回答

16

如果您正在使用Objective-C,为什么不尝试像这样做:

使用NSFileHandle:

NSString * path = @"/Users/pineapple/Desktop/finalproj/test242.txt";
NSFileHandle * fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
NSData * buffer = nil;
while ((buffer = [fileHandle readDataOfLength:1024])) {
  //do something with the buffer
}

或使用NSString:

NSString * fileContents = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];

或者如果你需要逐行读取它:

如何从NSFileHandle逐行读取数据?

在我看来,除非你有非常非常非常好的理由(例如使用O_SHLOCK打开文件),否则没有必要降到C级别的文件IO函数。


目标是逐个单词从文件中读取文本。我对Objective-C还很陌生,但至少我知道如何使用C函数来管理文本文件。 - user503707
2
这是正确的。如果文件不一定包含字符串数据(即原始字节),请使用NSData对象和其dataWithContentsOfFile构造函数,您就不必担心NSString对字符串编码的自动解释。 - Jon Shier

6
你的文件存储在UTF-16(Unicode)中。文件中的第一个字符是“L”,其代码点为0x4C。文件的前4个字节为FF FE 4C 00,它们是字节顺序标记(BOM)和字母L以UTF-16编码的两个字节。 fgets不支持Unicode,因此它正在寻找换行符'\n',它的字节为0x0A。最有可能发生在Unicode换行符的第一个字节上(两个字节0A 00),但也可能发生在许多其他非换行符字符上,例如U+010A(带点大写拉丁字母A)或古木基或古吉拉特文(U+0A00至U+0AFF)中的任何内容。
无论如何,现在存入缓冲区的数据有很多嵌入的空值,看起来像FF FE 4C 00 47 00 4F 00 4F 00 0A 00。 NUL(0x00)是C字符串终止符,因此当您尝试使用printf打印此内容时,它会停在第一个null处,而您只会看到\377\376L\377\376是字节FF FE的八进制表示。

解决方法是将文本文件转换为单字节编码,例如ISO 8859-1或UTF-8。请注意,大多数单字节编码(除了UTF-8)不能编码Unicode字符的全部范围,因此如果需要Unicode,则强烈建议使用UTF-8。或者,您可以将程序转换为Unicode-aware,但是这样一来,您就不能再使用许多标准库函数(例如fgetsprintf),并且需要在所有地方使用代替。


或者直接使用能够本地理解UTF16的东西,比如NSString - Dave DeLong
1
啊,戴夫,你们这些孩子们今天用着花哨的编码方式、高级框架,现在甚至还有节奏音乐,你们会毁掉我们美好的世界... - w-m

3

如果您不介意读取文件的全部内容,可以按照以下方式进行:

NSData* myData = [NSData dataWithContentsOfFile:myFileWithPath];

然后您可以根据需要对数据进行操作。如果文件不存在,您将得到nil。

如果您假设该文件中包含文本(字符串)数据,则还可以执行以下操作,然后将其解析为NSString:

NSString* myString = [[NSString alloc] initWithBytes:[myData bytes] length:[myData length] encoding:NSUTF8StringEncoding];

既然您提到您对Objective-C相对较新,那么您可以比较好地搜索NSStrings。在此查看更多信息。


我一定是在试图修复它时犯了这个错误。我将其编辑为printf(“%s yeh \n”,wah); 但它仍然存在相同的问题。 - user503707
保罗是正确的,如果没有更多信息,我们几乎无能为力。您确定您的文件存在并且fgets正在读取数据吗?尝试首先将wah设置为某些内容,以确保垃圾不仅仅是未初始化的数据,例如:char wah [200] =“hello”; - slycrel
我尝试将wah初始化为某些内容,但程序运行时它打印出\377\376H test。此外,我现在正在检查,文件确实存在。 - user503707
这似乎是一个编码问题。你可能正在读取数据,但sprintf尝试将其作为ASCII C字符串而不是Unicode字符串打印出来。我会更新我的帖子,包括从NSData转换为NSString的转换。 - slycrel

1
我也希望如此,并认为“改为这样做”并没有回答问题,下面是一个可行的示例。请注意,fgets会读取换行符,并将其附加到您的文本中。
NSString * fName = [[NSBundle mainBundle] pathForResource:@"Sample" ofType:@"txt"];
FILE *fileHandle = fopen([fName UTF8String],"r");
char space[1024];
while (fgets(space, 1024, fileHandle) != NULL)
{
    NSLog(@"space = %s", space);
}

fclose(fileHandle);

0
Slycrel已经解决了。在此基础上,以下是另一种将该数据转换为字符串的方法(我认为更简单):
NSString *myFileString = [[NSString alloc] initWithData:someData encoding:NSUTF8StringEncoding];

这将使用指定的NSData直接声明一个新的NSString。


0
 printf("%s test\n");

你没有将字符串传递给printf。尝试:
 printf("%s test\n", wah);

此外,如果您的文件包含一行超过200个字符,fgets将读取200个字符到wah中 - 然后在末尾添加一个NUL,这将超出wah的末尾(因为您声明它为200个字符),并且会覆盖一些随机内容,导致程序的行为未定义,并可能导致猫着火。

我在尝试修复它时一定犯了这个 bug。我编辑成 printf("%s yeh\n", wah);,但它仍有同样的问题。 - user503707
你的文件存在吗?你没有检查fopen的成功。 - The Archetypal Paul

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接