ページ 1 / 1
複数のテキストファイルの扱い方
Posted: 2019年3月03日(日) 14:45
by べけん
1.txt,2.txt,3.txt・・・のような連続したテキストファイルを上から18行削除するという処理を行おうとしたのですがload errorと出てしまいます。どこが間違っているかご指摘お願いしたいです。よろしくお願いします。
コード:
#include <stdio.h>
int main(void)
{
int i,j,l;
int line = 0; // 行数
char arr[3000][50], filepath[256];
FILE *f;
for(l = 0; l < 17; l++ )
{
sprintf(filepath,"%d.txt",l);
f = fopen(filepath, "r");
if(f == NULL)
{
printf("load error");
return -1;
}
// arr配列に1行ずつ格納
for(i = 0; i < sizeof(arr)/sizeof(arr[0]) && fgets(arr[i], sizeof(arr[i]), f); i++)
{
line++; // テキストファイルの行数
}
fclose(f);
for(j = 0; j < 18; j++)
{
arr[j][0] = '\0'; // 消したい行の先頭文字を\0にする
}
//for(k = 4; k < 6; k++)
//{
//arr[k][0] = '\0'; // 消したい行の先頭文字を\0にする
//}
f = fopen(filepath, "w");
if(f == NULL)
{arr[3][0] = '\0';
printf("load error");
return -1;
}
for(i = 0; i < line; i++)
{
if(arr[i][0] != '\0')
{
fputs(arr[i], f);
}
}
fclose(f);
}
return 0;
}
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月03日(日) 16:33
by かずま
べけん さんが書きました: ↑6年前
1.txt,2.txt,3.txt・・・のような連続したテキストファイルを上から18行削除するという処理を行おうとしたのですがload errorと出てしまいます。どこが間違っているかご指摘お願いしたいです。よろしくお願いします。
printf("load error"); ではなく、puts(filepath); としてみてください。
そのプログラムでは、まず 0.txt をオープンしようとしています。
また、削除したいファイルがどこにあり、
プログラムをどこで動かすかにもよります。
ファイル名を絶対パスにしたほうが良いかもしれません。
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月03日(日) 17:21
by べけん
ご返信ありがとうございます。
ご指摘していただいた通りprintfをputsに置き換えてプログラムを動かしたところ2.txtまでは処理がうまくいったのですが3.txt以降の処理が行われていませんでした。
この原因はプログラム側のほうにあったりしますでしょうか?
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月03日(日) 18:00
by みけCAT
printfをputsに置き換えずプログラムを動かしたところ、
自分の環境ではload errorが出ずに処理を行うことができました。
全角の数字や空白文字が混ざっているなど、処理対象のファイル名が間違っている可能性が考えられます。
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月03日(日) 18:11
by みけCAT
オフトピック
一応「テキストファイルを作るプログラム」のC言語版も置いておきます。
► スポイラーを表示
コード:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(void) {
const char* chars = "abcdefghijklmnopqrstuvwxyz";
size_t cnum = strlen(chars);
int i, j, k;
for (i = 0; i < 17; i++) {
int lno = rand() % 150 + 50;
char filename[256];
FILE* fp;
snprintf(filename, sizeof(filename), "%d.txt", i);
if ((fp = fopen(filename, "w")) == NULL) {
fprintf(stderr, "open %s failed\n", filename);
return 1;
}
for (j = 1; j <= lno; j++) {
int dlen = rand() % 30 + 10;
char data[64];
for (k = 0; k < dlen; k++) {
data[k] = chars[rand() % cnum];
}
data[dlen] = '\0';
fprintf(fp, "%03d:%s\n", j, data);
}
fclose(fp);
}
return 0;
}
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 00:30
by べけん
みけCATさん
ご丁寧にご指摘ありがとうございます!
一度プログラムのほう動かしてみます!
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 11:01
by YuO
fopenだと,非標準動作ではあるものの伝統的にエラーの場合はerrnoに値を設定します。
このため,errnoを調べたり,perrorでエラーを表示したりしてみると,原因がわかる場合があります。
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 12:17
by みけCAT
YuO さんが書きました: ↑6年前
fopenだと,非標準動作ではあるものの伝統的にエラーの場合はerrnoに値を設定します。
C言語の標準には含まれていませんが、POSIXの標準には含まれているようです。
fopen
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 14:10
by べけん
みけCAT さんが書きました: ↑6年前
printfをputsに置き換えずプログラムを動かしたところ、
自分の環境ではload errorが出ずに処理を行うことができました。
全角の数字や空白文字が混ざっているなど、処理対象のファイル名が間違っている可能性が考えられます。
3.txt以降の処理がうまくいかなかった原因についてですがおそらく一つ一つのファイルの分量が大きくchar arr[]の範囲が足らなかったのが影響していたようでした。しかし、テキストファイルは30近くあるのですがchar arr[]の[]内を100000といったかなり大きな値に変更したところ処理がされませんでした。おそらくchar arr[]の上限値に達したからだと思われますが、ほかの型で置き換えるなどしてこの上限以上にすることなどは可能でしょうか?
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 15:34
by かずま
べけん さんが書きました: ↑6年前
3.txt以降の処理がうまくいかなかった原因についてですがおそらく一つ一つのファイルの分量が大きくchar arr[]の範囲が足らなかったのが影響していたようでした。
おそらくなどと言わずに、3.txt のサイズ、行数、行内の文字数の最大値を調べてください。
べけん さんが書きました: ↑6年前
しかし、テキストファイルは30近くあるのですがchar arr[]の[]内を100000といったかなり大きな値に変更したところ処理がされませんでした。
arr は main のローカル変数で自動変数なので、確保できるサイズが限られます。
static char arr[100000][500]; のように static を付けて静的に確保するか、
関数の外側でグローバル変数として宣言し、静的に確保するようにしてみてください。
べけん さんが書きました: ↑6年前
ほかの型で置き換えるなどしてこの上限以上にすることなどは可能でしょうか?
必要な領域を動的に確保すればよいでしょう。
ちょっと書いてみました。
コード:
#include <stdio.h> // fopen, fclose, fgetc, fread, fwrite,
// fgetpos, fputpos, fseek, sprintf, perror
#include <stdlib.h> // malloc, free
#define NFILE 3 // 1.txt~3.txt
#define LINE 18
int main(void)
{
for (int i = 1; i <= NFILE; i++) {
char path[256];
sprintf(path, "%d.txt", i);
FILE *fp = fopen(path, "rb");
if (!fp) { perror(path); return 1; }
fpos_t p0, p1;
fseek(fp, 0, SEEK_END); // 読み込み位置を最後に移動
fgetpos(fp, &p1); // 最後の位置を取得
rewind(fp); // 読み込み位置を先頭に移動
int c, n = 0;
while ((c = fgetc(fp)) != EOF)
if (c == '\n' && ++n == LINE) break;
fgetpos(fp, &p0); // 指定行数読み込み後の位置を取得
size_t len = p1 - p0; // 先頭部分削除後のサイズ
char *buf = malloc(len); // C++ なら char *buf = new char[len];
if (!buf) { perror("malloc"); return 2; }
fread(buf, 1, len, fp);
fclose(fp);
fp = fopen(path, "wb");
if (!fp) { perror(path); return 3; }
fwrite(buf, 1, len, fp);
fclose(fp);
free(buf); // C++ なら delete[] buf;
}
return 0;
}
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 16:34
by べけん
static char arrにすることで無事解決しました!
ありがとうございます!
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 16:47
by かずま
べけん さんが書きました: ↑6年前
static char arrにすることで無事解決しました!
グローバル変数にすることも試してみましたか?
領域の動的確保は理解したのですか?
3.txt のサイズ、行数、行内の文字数の最大値を教えてください。
エラーの原因をとことん追求しないと、これからも困りますよ。
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月04日(月) 21:06
by かずま
Linux ではこんなこともできます。
コード:
#include <stdio.h> // sprintf
#include <stdlib.h> // system
int main(void)
{
for (int i = 1; i <= 3; i++) { // 1.txt~3.txt
char cmd[1024];
sprintf(cmd, "mv %d.txt _; sed -n '19,$p' _ >%d.txt; rm _", i, i);
system(cmd);
}
}
Windows でも cygwin をインストールしていれば gcc でできるでしょう。
Re: 複数のテキストファイルの扱い方
Posted: 2019年3月05日(火) 00:16
by かずま
すみません。mv %d.txt _ を cp %d.txt _ に変更します。
こうすると、sed の >%d.txt により、元のファイルの内容が
更新されますが、ファイルの属性(read/write モードや所有者
や i-node番号など)は元のままです。
mv にすると、sed の >%d.txt により新規ファイルが作成される
のでファイルの属性は保存されません。
ファイルの属性の保存が必要なければ、一時ファイルの _ を
使用せず、sed の -i オプションで済みます。
コード:
sprintf(cmd, "sed -i -n '19,$p' _ >%d.txt", i);
system(cmd);