FileRead_open()の使い方がいまいちわかりません。

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
ゆーいち

FileRead_open()の使い方がいまいちわかりません。

#1

投稿記事 by ゆーいち » 5年前

自分のソース内ではcsvファイルを読んで処理する関数を作っており、

宣言
void LoadData(int,int,string);
定義
void LoadData(int y,int x,string s){
 処理内容
 CSVとその縦横の数値を受け取り、
 CVSの中の文字を一文字ずつ読んで
 指定の変数に格納していく
}
呼び出し
LoadData(4,4,"media/data.csv");

といった感じです。

今回「FileRead_open()を使用すれば、アーカイブ内の任意のファイルを読み込むことができる。」
とこちらでアドバイスを受けたので、csvが入ったフォルダ「media」をarchiveし、media.dxaを作りました(pass付き。

しかし、見てわかる様に、私の作った関数では
LoadData(4,4,"media/data.csv");と、引数でcsvを直接呼んでます。
この場合、どの段階?でFileRead_open( char *FilePath, int ASync ) を
使えばいいのでしょうか?
DXライブラリ置き場のサンプルでは「.cpp」「.bmp」しか使っていないので
いまいちわかりません。

そもそも、私はarchiveファイルを利用したことあるんですが、
mainのWINAPI WinMainのところで
SetDXArchiveKeyString( "パスワード" );を記載していれば
各cppでarchiveしたファイル内の画像は通常と変わらなく呼び出し放題です。
なぜ、csvのファイルだとこれでは読めないのでしょうか。

自分の作った冒頭の関数でarchiveしたcsvファイルを読み込みたい場合
どこでなにをすべきなのか教えてください
お願いします!

ゆーいち

Re: FileRead_open()の使い方がいまいちわかりません。

#2

投稿記事 by ゆーいち » 5年前

fp = FileRead_open("csvファイル名");

この場合、fpの中にcsvファイルの中身がそのまま
入っていると思っていいんでしょうか?

つまり、
fp =FileRead_open("media/data.csv");
LoadData(4,4,fp);

こんな感じでいけますか?

かずま

Re: FileRead_open()の使い方がいまいちわかりません。

#3

投稿記事 by かずま » 5年前

次のコードは参考になりますか?

コード:

#include "DxLib.h"
#include <string>
using std::string;

int data[4][4];
int err;

void LoadData(int y, int x, string s)
{
    int fh = FileRead_open(s.c_str());  // fh: file handle
    if (fh == 0) { err = 1; return; }
    for (int i = 0; i < y; i++)
        for (int j = 0; j < x; j++)
            if (FileRead_scanf(fh, "%d%*c", &data[i][j]) != 1) {
                err = 2; goto ret;
            }
ret:
    FileRead_close(fh);
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hpi, LPSTR cl, int cs)
{
    if (DxLib_Init() == -1) return -1 ;

    err = 0;
    LoadData(4, 4, "media/data.csv");
    if (err != 0) goto ret;

    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            DrawFormatString(j*60, i*40+100, GetColor(0, 255, 255),
                " %7d", data[i][j]);

    WaitKey();
ret:
    DxLib_End();
    return 0;
}
media/data.csv

コード:

141,-42,1356,173
20,50,-8,22
3606,79,314,15
-92,6535,89,79

ゆーいち

Re: FileRead_open()の使い方がいまいちわかりません。

#4

投稿記事 by ゆーいち » 5年前

かずまさん、回答をありがとうございます。
見せて頂いて、なにかわかりかけてます!
ただ、すみません、
FileRead_open(s.c_str()
この「.c_str()」は引数から受け取ったsの
なにを表しているのか
解説お願いできますか?

かずま

Re: FileRead_open()の使い方がいまいちわかりません。

#5

投稿記事 by かずま » 5年前

DxLib を見ると
extern int FileRead_open(const TCHAR *FilePath, int ASync = FALSE);
と宣言されています。
UNICODE が define されていないと、TCHAR は char です。

void LoadData(int y, int x, string s) の s は string なので、
そのままでは、FilePath に渡せません。
そこで string のメンバ関数である c_str() を使って、
s の中にある文字列のアドレス(const char *) を取得しています。

LoadData のプロトタイプを変更してよければ
string を使わず、次のように書けます。

コード:

#include "DxLib.h"

int data[4][4];

int LoadData(int y, int x, const char *s)
{
    int err = 0;
    int fh = FileRead_open(s);  // fh: file handle
    if (fh == 0) return 1;
    for (int i = 0; i < y; i++)
        for (int j = 0; j < x; j++)
            if (FileRead_scanf(fh, "%d%*c", &data[i][j]) != 1) {
                err = 2; goto ret;
            }
ret:
    FileRead_close(fh);
    return err;
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hpi, LPSTR cl, int cs)
{
    if (DxLib_Init() == -1) return -1 ;

    int err = LoadData(4, 4, "media/data.csv");
    if (err != 0) goto ret;

    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            DrawFormatString(j*60, i*40+100, GetColor(0, 255, 255),
                "%8d", data[i][j]);

    WaitKey();
ret:
    DxLib_End();
    return 0;
}

ゆーいち

Re: FileRead_open()の使い方がいまいちわかりません。

#6

投稿記事 by ゆーいち » 5年前

かずまさん、自分なりにFileRead_open(~.c_str()を組み込んでみました。
これでは動きませんか?
ちなみに呼び出しはLoadData(120,120,"csv/map.csv");とします
※尚、第三引数のstringを変更することはできません。
呼び出し時、第三引数はcsvのパスを入力したいので。。。

コード:

void MapCheck::LoadData(int y,int x,string s){

	m_line = y;		//縦
	m_col = x;		//横

	int line = 0;
	int count = 0;
	int sum = 0;
	int nokorinoketa=0;

	int fh = FileRead_open(s.c_str());
	string buf[3000];

	Map.resize(m_line);//resizeで行数を決める
	for(int i = 0; i<m_line; i++){
		Map[i].resize(m_col);
		}//resizeで各行の列数を決める

	while(fh && getline(fh,buf[line])){
		line++;
		}

	for(int line=0; line<y; line++){
		for(int col=0; col<x; col++){
			if(col < x-1){
				sum = buf[line][count]-48;
				count++;
				while(isdigit(buf[line][count])){
					sum = sum*10 + (buf[line][count])-48;
					count++;
					}				
				Map[line][col] = sum;//Noが格納
				count++;
			}
			if(col == x-1){//最後の数字
				nokorinoketa = buf[line].size()-count;
				sum = buf[line][count] - 48;
				while(nokorinoketa > 1){
					count++;
					sum = sum*10 + (buf[line][count])-48;
					nokorinoketa--;
				}
				Map[line][col] = sum;//Noが格納
			}
		}
		count=0;
	}
	FileRead_close(fh);
}

自分のやりたいことは、第三引数でうけとったcsvパスの中身を
あらかじめ自分で用意していたMap配列の各要素に一文字ずつ格納させる。
ちなみにこのMap配列の要素数は決めておらず、
vector<vector<int>>Map;と宣言しており、
第一、第二引数を受け取ってから要素数を決定させています。

いろいろと不細工なソースですが
おかしいところがあれば、ご指摘頂ければ幸いです。

かずま

Re: FileRead_open()の使い方がいまいちわかりません。

#7

投稿記事 by かずま » 5年前

getline を定義してやれば、そのコードで動くことを確認しました。

コード:

#include "DxLib.h"
#include <string>
#include <vector>

using namespace std;

class MapCheck {
	vector<vector<int>> Map;
	int m_line, m_col;
public:
	void LoadData(int y, int x, string s);
	void ShowData(int y, int x);
	bool getline(int fh, string& s);
};

void MapCheck::LoadData(int y,int x,string s){

	m_line = y;		//縦
	m_col = x;		//横

	int line = 0;
	int count = 0;
	int sum = 0;
	int nokorinoketa=0;

	int fh = FileRead_open(s.c_str());
	string buf[3000];

	Map.resize(m_line);//resizeで行数を決める
	for(int i = 0; i<m_line; i++){
		Map[i].resize(m_col);
		}//resizeで各行の列数を決める

	while(fh && getline(fh,buf[line])){
		line++;
		}

	for(int line=0; line<y; line++){
		for(int col=0; col<x; col++){
			if(col < x-1){
				sum = buf[line][count]-48;
				count++;
				while(isdigit(buf[line][count])){
					sum = sum*10 + (buf[line][count])-48;
					count++;
					}				
				Map[line][col] = sum;//Noが格納
				count++;
			}
			if(col == x-1){//最後の数字
				nokorinoketa = buf[line].size()-count;
				sum = buf[line][count] - 48;
				while(nokorinoketa > 1){
					count++;
					sum = sum*10 + (buf[line][count])-48;
					nokorinoketa--;
				}
				Map[line][col] = sum;//Noが格納
			}
		}
		count=0;
	}
	FileRead_close(fh);
}

void MapCheck::ShowData(int y, int x)
{
	for (int i = 0; i < y; i++)
		for (int j = 0; j < x; j++)
			DrawFormatString(j*60, i*40+100, GetColor(0, 255, 255),
				"%8d", Map[i][j]);
}

bool MapCheck::getline(int fh, string& s)
{
	char buf[1024];
	if (FileRead_gets(buf, sizeof buf, fh) == -1) return false;
	s = buf;
	return true;
}

int WINAPI WinMain(HINSTANCE hi, HINSTANCE hpi, LPSTR cl, int cs)
{
	if (DxLib_Init() == -1) return -1 ;

	MapCheck mc;
	mc.LoadData(4, 4, "media/data.csv");
	mc.ShowData(4, 4);

	WaitKey();
ret:
	DxLib_End();
	return 0;
}
FileRead_open() に失敗した場合のことは考えなくていいのですね?

行単位で読み込んで、自分で文字列を数値に直したいのなら、負の数の
入力はないとして、次のように書けばよいのではないでしょうか?

コード:

void MapCheck::LoadData(int y, int x, string s)
{
	m_line = y;
	m_col = x;

	Map.resize(m_line);
	for (int i = 0; i < m_line; i++) Map[i].resize(m_col);

	int fh = FileRead_open(s.c_str());

	for (int line = 0; line < m_line; line++) {
		char buf[1024];
		FileRead_gets(buf, sizeof buf, fh);
		int i = 0;
		for (int col = 0; col < m_col; col++) {
			int sum = 0;
			while (isdigit((unsigned char)buf[i]))
				sum = sum*10 + (buf[i++] - '0');
			Map[line][col] = sum;
			i++; // skip ','
		}
	}
	FileRead_close(fh);
}

ゆーいち

Re: FileRead_open()の使い方がいまいちわかりません。

#8

投稿記事 by ゆーいち » 5年前

かずまさん、ありがとうございます。
確かにかずまさんの言う通り、getlineを定義してやれば、
私の今回のコードは動きました。
コレで解決かと思ったのですが、、、、
しかし、やっぱりreleaseした後、
archiveした状態のcsvファイルでは、
実行しても正常に読み込んではくれていませんでした。

自分の一番の目的は、DXライブラリで製作したゲームを
配布する時に、csvファイルをarchiveしておき、
それをゲームで読み込ませて扱うことなんですが、
今回の話でいえば、csvファイルを読んで
マップ配列に数値を入れるプログラムは
ifstreamを使うことで自分は簡単に行えていたのですが、
releaseして、そのcsvファイルが入ったmediaフォルダを
archiveさせてしまうと、そのままのプログラム文じゃ
csvファイルを正常に読み込むことができなくなったのです。

なので、私はこの掲示板で、どうすればいいのか
質問させて頂いたんですが
そしたらarchiveしたcsvファイルを読む場合は
「FileRead」を使わないといけないと助言されました。
なので、私は、ifstreamでcsvファイルを読んでたプログラムを
FileReadで読むプログラムに改造しなければならなくなりました。
今回、かずまさんのおかげで無事csvファイルをFileReadで開いて
配列に入れ込むプログラムが完成できたというのに
ゲームをreleaseし、csvファイルを入れたフォルダを
archiveし、exeファイルを実行したところ
やはりマップは正常に表示されていない状態でした。
ifstreamで読ませてたときと同じ状況でした。

FileReadで読むようにしたのに、、、なにがいけないのでしょうか?
かずまさん、お願いします。
すみませんが、今回のソースをreleaseして、
csvファイルを入れたmediaフォルダをarchiveして
「media.dxa」にしてそれと実行ファイルとで立ち上げて
確認もらえませんか?
Map配列には正常な数値が入っていないはずです。
どうしても私の言ってることを見て頂きたいのです。

かずま

Re: FileRead_open()の使い方がいまいちわかりません。

#9

投稿記事 by かずま » 5年前

「release して」の意味がよくわかりませんが、
FileRead_open するファイル名を絶対パスにすればよいのでは?

例えば、c:/tmp/hoge/media.dxa がある場合、
mc.LoadData(4, 4, "c:/tmp/hoge/media/data.csv");

ゆーいち

Re: FileRead_open()の使い方がいまいちわかりません。

#10

投稿記事 by ゆーいち » 5年前

かずまさん、レスありがとうございます。
DXライブラリのarchiveを熟知してる方々もこの掲示板にはいると思いますが
そういう方々がこの質問をスルーし、なんらアドバイスをくれることの無い中、
付き合ってくださって、本当に感謝しています。

>「release して」の意味がよくわかりませんが、

Releaseビルドでexeファイルを作ることです。
ビジュアルスタジオでゲームを完成させて最後、
実行可能アプリケーションを作成することです。

>FileRead_open するファイル名を絶対パスにすればよいのでは?

もちろん、ファイル名は絶対パスを入力してますし
ビジュアルスタジオ上で、実行したときは、正常に読み込み、一切問題ないのです。
問題は、releaseビルドして、つまり、exeファイルにして、外でそのゲームを実行する時です。
主に他人様に配布する時にreleaseビルドするわけですが
外部ファイルであるCSVも情報を漏らしたく無いので隠蔽目的でそのフォルダをアーカイブします。
そのアーカイブしたCSVを、今回のソースでは正常に読み込めないのです。

「archive化したテキストファイルは改行コード\nが消えたバイナリファイル化される」
という意見も聞きましたが、かずまさん、もしこの言葉が事実なら
私たちのこのソースではうまく読み込めない可能性や要因がわかりませんか?
DXライブラrのarchiveの説明には一切そんなことかいてないのでほんと困ってます。

返信

“C言語何でも質問掲示板” へ戻る