連番ファイルをランダムに読み込む方法

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

連番ファイルをランダムに読み込む方法

#1

投稿記事 by fq47 » 4ヶ月前

同じフォルダに入っている連番ファイル(1.txt,2.txt,・・・100.txt)をランダムに読み込ませたいのですが、どうすればいいのでしょうか?
C++またはCで教えていただけないでしょうか?

m3908714035
記事: 17
登録日時: 4ヶ月前

Re: 連番ファイルをランダムに読み込む方法

#2

投稿記事 by m3908714035 » 4ヶ月前

txtファイルの中身が分からないので、とりあえず1.txtから100.txtまでに1.txtなら1、2.txtなら2、100.txtなら100と記入されていることを前提にプログラムを組んでみました。

code:

コード:

#include <iostream>
#include <random>
#include <vector>
#include <numeric>
#include <string>
#include <fstream>
#include <sstream>
using namespace std;

int main() {
	random_device rnd; // 非決定的な乱数生成器
	mt19937 mt(rnd()); // 疑似乱数(決定的な乱数)生成器
	vector<int> filenumber(100); // 乱数置き場
	iota(filenumber.begin(), filenumber.end(), 1); // 配列内を 1~100 までの数字で埋める
	shuffle(filenumber.begin(), filenumber.end(), mt); // 疑似乱数生成器を用いてシャッフル
	string filename; // ファイル名
	stringstream receiver; // ファイル内文字列の受け取り場所
	vector<string> data(100); // ファイル内文字列の最終保管場所
	for (int i = 0; i < 100; i++) {
		receiver.str(""); // バッファをクリア
		receiver.clear(stringstream::goodbit); // ストリームの状態をクリア
		filename = to_string(filenumber[i]) + ".txt"; // ファイル名指定
		ifstream fin(filename); // ファイルの読み込み
		if (!fin) { return 1; } // ファイルが読み込めなかった場合エラー
		receiver << fin.rdbuf(); // ファイル内文字列をコピー
		fin.close(); // ファイルを閉じる
		receiver >> data[i]; // ファイル内文字列を保管
	}
	return 0;
}
これに以下のコードを加えて出力させてみます。

additional code:

コード:

for (int i = 0; i < 100; i++) {
		cout << data[i] << endl;
}
output:

コード:

14
61
100
38
88
73
81
64
90
1
15
2
71
6
7
20
63
13
91
84
27
41
5
10
51
99
57
65
58
87
77
89
69
50
67
47
74
8
12
72
85
39
49
44
95
40
35
9
94
26
55
32
83
42
75
36
3
92
25
29
24
45
34
37
52
86
31
17
80
97
98
28
33
23
16
79
21
18
19
76
22
48
43
30
53
60
93
78
59
54
4
82
11
66
46
68
62
96
56
70
私はそこまでC++の関数(?)等に詳しくないので、ひたすらググってコードを作成しました。もしかするともっと簡潔に書けるのかもしれませんが参考程度になればと思い、投稿させていただきます。
ちなみに、連番ファイルの作成にあたっては以下のサイトを参考にしましたのでリンクを張っておきます。
[備忘録] C++における連番ファイルの作り方

分からないことあれば質問いただけるとこのプログラムに関してはお答え出来ると思いますので、返信は遅いかもしれませんが気軽にどうぞ。

m3908714035
記事: 17
登録日時: 4ヶ月前

Re: 連番ファイルをランダムに読み込む方法

#3

投稿記事 by m3908714035 » 4ヶ月前

※追記
今回はランダムに読み込みたいとのことでしたので、読み込むファイルを疑似乱数を用いてランダムにしましたが、差し支えないようなら素直に1.txtから100.txtまでをvector配列に入れてシャッフルしても良いと思います。まあ、シャッフルするのが先か後かという違いだけだとは思いますが…。

かずま

Re: 連番ファイルをランダムに読み込む方法

#4

投稿記事 by かずま » 4ヶ月前

fq47 さんが書きました:
4ヶ月前
同じフォルダに入っている連番ファイル(1.txt,2.txt,・・・100.txt)をランダムに読み込ませたいのですが、どうすればいいのでしょうか?
C++またはCで教えていただけないでしょうか?
単にファイル名を実行時に生成するだけの話ではないのですか?

コード:

	char name[8];
	sprintf(name, "%d.txt", rand() % 100 + 1);
	fp = fopen(name, "r");

かずま

Re: 連番ファイルをランダムに読み込む方法

#5

投稿記事 by かずま » 4ヶ月前

かずま さんが書きました:
4ヶ月前
単にファイル名を実行時に生成するだけの話ではないのですか?
すみません。私の勘違いかもしれません。
100個のファイルのうち、ランダムにどれか一つ読み込めばよいのかと
思っていました。
100個のファイル全部をランダムな順番で読み込むということでしょうか?

それなら、

コード:

#include <stdio.h>   // sprintf, printf, fopen, fclose, fgets, fputs
#include <stdlib.h>  // srand, rand
#include <time.h>    // time

#define N 100

int main(void)
{
	int a[N], i;
	srand(time(0));
	for (i = 0; i < N; i++) a[i] = i + 1;
	while (i > 0) {
		char name[16];
		int j = rand() % i;
		sprintf(name, "%d.txt", a[j]);
		a[j] = a[--i];
		FILE *fp = fopen(name, "r");
		if (!fp) { printf("can't open %s\n", name); return 1; }
		printf("=== %s ===\n", name);
		char buf[1024];
		while (fgets(buf, sizeof buf, fp))
			fputs(buf, stdout);
		fclose(fp);
	}
}
フォーラム(掲示板)ルールにあるように質問者は、回答に応答してください。
d. 義務行為

"C言語何でも質問掲示板"でのみ適用される事項
・複数の回答者がいた場合、都合の良い、または自分の気が向いた回答者にだけ返信を書かず、回答をくれた人 全員に対して出来る限りの返信を書きましょう。
・回答者のコメントの中に複数質問があった場合、出来る限りその全てに答えるようにしましょう。

かずま

Re: 連番ファイルをランダムに読み込む方法

#6

投稿記事 by かずま » 4ヶ月前

m3908714035 さんが書きました:
4ヶ月前

コード:

		receiver >> data[i]; // ファイル内文字列を保管
これでは、ファイル中の単語(空白を含まない文字列)を 1個しか
読み込めません。ファイル内の文字全部を取得したければ、
data[ i] = receiver.str(); としたほうが良いのではありませんか?

Cプログラムで、ファイルの内容をすべてメモリに読み込みたければ、
次のように書けます。

コード:

#include <stdio.h>   // sprintf, printf, fopen, fclose, fseek, rewind, fread, puts
#include <stdlib.h>  // srand, rand, malloc, free
#include <time.h>    // time

#define N 100

int main(void)
{
	int a[N], i, k = 0;
	char *data[N];
	srand(time(0));
	for (i = 0; i < N; i++) a[i] = i + 1;
	while (i > 0) {
		char name[16];
		int j = rand() % i;
		sprintf(name, "%d.txt", a[j]);
		a[j] = a[--i];
		FILE *fp = fopen(name, "r");
		if (!fp) { printf("can't open %s\n", name); return 1; }
		//printf("=== %s ===\n", name);
		fseek(fp, 0, SEEK_END);
		long n = ftell(fp);
		rewind(fp);
		data[k] = malloc(n + 1);
		if (!data[k]) return 2;
		n = fread(data[k], 1, n, fp);
		data[k++][n] = '\0';
		fclose(fp);
	}
	for (i = 0; i < N; i++) puts(data[i]);
	for (i = 0; i < N; i++) free(data[i]);
}
ただし、Windows では、ファイル中の改行は '\r' '\n' の 2文字であり、
fread がこれを '\n' 1文字に変換するので、fread で n の値は
行数分少なくなります。

m3908714035
記事: 17
登録日時: 4ヶ月前

Re: 連番ファイルをランダムに読み込む方法

#7

投稿記事 by m3908714035 » 4ヶ月前

かずま さんが書きました:
4ヶ月前
100個のファイルのうち、ランダムにどれか一つ読み込めばよいのかと
思っていました。
すみません。仰る通りかもしれません。コードの修正等ありがとうございます。

かずま

Re: 連番ファイルをランダムに読み込む方法

#8

投稿記事 by かずま » 4ヶ月前

#6 の Cプログラムを C++ に書き換えてみました。

コード:

#include <iostream> // cout
#include <fstream>  // ifstream
#include <string>   // to_string, getline
#include <random>   // randome_device, mt19937, unifortm_int_distribution

int main(void)
{
	using namespace std;
	mt19937 mt((random_device())());
	const int N = 100;
	int a[N];
	for (int i = 0; i < N; i++) a[i] = i + 1;
	string data[N];
	for (int j, i = N; --i >= 0; a[j] = a[i]) {
		j = uniform_int_distribution<int>(0, i)(mt);
		ifstream ifs(to_string(a[j]) + ".txt");
		if (!ifs || !getline(ifs, data[i], '\0')) return 1;
	}
	for (auto& s : data) cout << s;
}

かずま

Re: 連番ファイルをランダムに読み込む方法

#9

投稿記事 by かずま » 4ヶ月前

かずま さんが書きました:
4ヶ月前
#6 の Cプログラムを C++ に書き換えてみました。

コード:

		ifstream ifs(to_string(a[j]) + ".txt");
		if (!ifs || !getline(ifs, data[i], '\0')) return 1;
テキストファイルには '\0' がないと考えてgetline をこのように
使いましたが、'\0' があったとしても、とにかくファイル全体を
読み込みたいというのなら、次のように書けます。

コード:

		ifstream ifs(to_string(a[j]) + ".txt");
		if (!ifs) return 1;
		data[i] = string(istreambuf_iterator<char>(ifs), istreambuf_iterator<char>());
また、data[ i] は data[N-1]から data[0] まで逆順に読み込んでいます。
ランダムに読み込むんだから、これでもいいと思うんですが、
順番に読み込ませたければ、for の先頭に k = 0, を追加し、
data[k++] = にすればよいでしょう。

返信

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