使用COCOS2D-X进行文件输入/输出

6
我正在尝试加载一个名为 POSDATA.GAMEDATA 的逗号分隔文件。我在互联网上查找了几个地方,结果发现我需要进行一些微调和/或使用不同的类。
我尝试使用 ifstream。但是,它无法打开文件。Xcode 4.3.2 似乎找不到我的 POSDATA.GAMEDATA 文件。我还尝试使用 ofstream 创建文件,但在这两种情况下使用 open() 时,文件都没有被打开。
我的代码大致如下:
using namespace std;
void FileLoader::loadFile( string p_WhichFile ) {
   // Local Variables
   string thisLine;

   // Open POSDATA.GAMEDATA
   ifstream dataStream;
   dataStream.open( p_WhichFile.c_str( ) );

   // Check if file is opened
   if ( !dataStream ) {
      cerr << "[ ERROR ] Cannot load file:" << p_WhichFile.c_str( ) << endl;
      exit( 1 );
   }

   // Get lines of strings
   while ( getline( dataStream, thisLine ) ) {
      fileContents.push_back( thisLine ); // fileContents is a vector< string > object
   }

   dataStream.close( );
   cout << "[ NOTICE ] Finished reading file" << p_WhichFile << endl;
}

我看过了CCFileUtils,但似乎不知道如何使用它。 编辑:我尝试提供绝对路径( /Users/LanceGray/Documents/LanceDev/COCOS2DX/cocos2dx/TestGame/Data/POSDATA.GAMEDATA ),并且它起作用了。但是,由于游戏应该在iOS设备和Android上使用,因此每个设备上的路径不总是相同的。非常感谢您的任何帮助。

你正在使用Android或iOS开发吗?如果是Android,或者你计划同时支持两种操作系统,我认为最好使用CCFileUtils来避免使用Zip库。另一方面,如果是iOS,则可以直接使用fopen。我对ifstream不是很熟悉,无法提供太多帮助。 - m.ding
它应该同时用于iOS和Android。您能否给出一个使用CCFileUtilsfopen的小例子?与此同时,我会尝试寻找它们。 - alxcyl
3个回答

17

我通过使用CCFileUtils( )::sharedFileUtils( ) -> fullPathFromRelativePath( "POSDATA.GAMEDATA" );使其工作。

更详细的说明:

  1. 通过在左侧的项目树上右键单击,选择 右键菜单 -> 添加文件 将需要的文件添加到项目中。我创建了一个名为 Data 的新文件夹,与 ResourcesClasses 文件夹并列,并将我的 POSDATA.GAMEDATA 文件放在其中。在 Xcode 中,我创建了一个新的组,并将该文件添加到该组中。
  2. 然后使用 ifstream 打开文件。
  3. 打开文件时,使用 CCFileUtils( )::sharedFileUtils( ) -> fullPathFromRelativePath( ) 获取文件的绝对路径,在 fullPathFromRelativePath( ) 中以文件名作为参数。
  4. 尝试运行它,应该可以正常工作。

一个小例子:

// FileReader.h
#include "cocos2d.h"

using namespace std;
using namespace cocos2d;

class FileReader {
private:
   vector< string > mFileContents;

public:
   FileReader( string pFileName, char pMode = 'r' );
};

// FileReader.cpp
#include "FileReader.h"
#include <fstream>
#include "cocos2d.h"

using namespace cocos2d;
using namespace std;

FileReader::FileReader( string pFileName, char pMode ) {
   // Create input file stream
   ifstream inputStream;
   string thisLine;

   // Open file
   inputStream.open( CCFileUtils( )::sharedFileUtils( ) -> fullPathFromRelativePath( pFileName ).c_str( ) );

   // Check if it is open
   if ( !inputStream.is_open( ) ) {
      cerr << "[ ERROR ] Cannot open file: " << pFileName.c_str( ) << endl;
      exit( 1 );
   }

   while ( getline( inputStream, thisLine ) ) {
      // Put all lines in vector
      mFileContents.push_back( thisLine );
   }

   inputStream.close( );
   cout << "[ NOTICE ] Finished opening file: " << pFileName.c_str( ) << endl;
}
这个类将加载名为pFileName的文件,并将其放置在其成员变量mFileContents中。(请注意,它应该有一个public get函数,如vector< string > getFileContents( )来访问mFileContents,因为它是private)。 编辑:上面的示例适用于iOS,但在Android设备上无法使用。因此,为了解决这个问题,我们不再使用ifstream,而是改用CCFileUtils::sharedUtils( ) -> getFileData( )。与CCFileUtils::sharedUtils( ) -> fullPathFromRelativePath( )一起使用,我们将能够实现我们的目标,在iOS和Android上都能读取纯文本文件。 FileReader类应该像这样:
// FileReader.cpp
#include "FileReader.h"
#include <fstream>
#include "cocos2d.h"

using namespace cocos2d;
using namespace std;

FileReader::FileReader( string pFileName, char pMode ) {
   // Initialize variables needed
   unsigned long fileSize = 0;
   unsigned char * fileContents = NULL;
   string thisLine, result, fullPath, contents;

   // Get absolute path of file
   fullPath = CCFileUtils::sharedFileUtils( ) -> fullPathFromRelativePath( pFileName.c_str( ) );

   // Get data of file
   fileContents = CCFileUtils::sharedFileUtils( ) -> getFileData( fullPath.c_str( ) , "r", &fileSize );
   contents.append( ( char * ) fileContents );

   // Create a string stream so that we can use getline( ) on it
   istringstream fileStringStream( contents );

   // Get file contents line by line
   while ( getline( fileStringStream, thisLine ) ) {
      // Put all lines in vector
      mFileContents.push_back( thisLine );
   }

   // After this, mFileContents will have an extra entry and will have the value '\x04'.
   // We should remove this by popping it out the vector.
   mFileContents.pop_back( );

   // Delete buffer created by fileContents. This part is required.
   if ( fileContents ) {
      delete[ ] fileContents;
      fileContents = NULL;
   }

   // For testing purposes
   cout << "[ NOTICE ] Finished opening file: " << pFileName.c_str( ) << endl;
}

如果你在Android上有一个巨大的数据文件,并且无法使用getFileData()读取整个文件,那该怎么办呢?拥有更直接的访问方式会很好...就像fseek一样。 - Cristi

2
// For versions less than v2.0.1
// The version I am using is 0.12.0
unsigned long fileSize = 0;
char* pBuffer = CCFileUltils::getFileData("relative_path","r",&fileSize);
CCLOG("Data is %s",pBuffer);

谢谢你的帮助。不过我已经通过使用CCFileUtils让它正常工作了。 - alxcyl
我尝试使用getFileData(),但是出现了错误,显示Assertion failed: (pszFileName != __null && pSize != __null && pszMode != __null), function getFileData, file CCFileUtils.mm, line 450. 我的使用方式如下:unsigned char * posdataLoc = CCFileUtils::sharedFileUtils() -> getFileData( "POSDATA.GAMEDATA", "r", 0 ); - alxcyl
我现在已将 getFileData() 功能实现了。然而,当我在控制台使用cout 输出它时,末尾会显示额外的随机字符。很奇怪。 - alxcyl

0

这不是一个答案,最多只能算是一个评论。 - nikhil

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