複数のテキストファイルの扱い方

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
べけん
記事: 21
登録日時: 4ヶ月前

複数のテキストファイルの扱い方

#1

投稿記事 by べけん » 4ヶ月前

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: 複数のテキストファイルの扱い方

#2

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

べけん さんが書きました:
4ヶ月前
1.txt,2.txt,3.txt・・・のような連続したテキストファイルを上から18行削除するという処理を行おうとしたのですがload errorと出てしまいます。どこが間違っているかご指摘お願いしたいです。よろしくお願いします。
printf("load error"); ではなく、puts(filepath); としてみてください。
そのプログラムでは、まず 0.txt をオープンしようとしています。

また、削除したいファイルがどこにあり、
プログラムをどこで動かすかにもよります。
ファイル名を絶対パスにしたほうが良いかもしれません。

べけん
記事: 21
登録日時: 4ヶ月前

Re: 複数のテキストファイルの扱い方

#3

投稿記事 by べけん » 4ヶ月前

ご返信ありがとうございます。

ご指摘していただいた通りprintfをputsに置き換えてプログラムを動かしたところ2.txtまでは処理がうまくいったのですが3.txt以降の処理が行われていませんでした。

この原因はプログラム側のほうにあったりしますでしょうか?

アバター
みけCAT
記事: 6148
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: 複数のテキストファイルの扱い方

#4

投稿記事 by みけCAT » 4ヶ月前

printfをputsに置き換えずプログラムを動かしたところ、
自分の環境ではload errorが出ずに処理を行うことができました。
全角の数字や空白文字が混ざっているなど、処理対象のファイル名が間違っている可能性が考えられます。
添付ファイル
gen.zip
テキストファイルを作るプログラム(Perl)
(537 バイト) ダウンロード数: 4 回
textfiles.zip
テスト用テキストファイル
(43.99 KiB) ダウンロード数: 3 回
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6148
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: 複数のテキストファイルの扱い方

#5

投稿記事 by みけCAT » 4ヶ月前

オフトピック
一応「テキストファイルを作るプログラム」のC言語版も置いておきます。
► スポイラーを表示
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

べけん
記事: 21
登録日時: 4ヶ月前

Re: 複数のテキストファイルの扱い方

#6

投稿記事 by べけん » 4ヶ月前

みけCATさん
ご丁寧にご指摘ありがとうございます!
一度プログラムのほう動かしてみます!

YuO
記事: 936
登録日時: 8年前
住所: 東京都世田谷区

Re: 複数のテキストファイルの扱い方

#7

投稿記事 by YuO » 4ヶ月前

fopenだと,非標準動作ではあるものの伝統的にエラーの場合はerrnoに値を設定します。
このため,errnoを調べたり,perrorでエラーを表示したりしてみると,原因がわかる場合があります。

アバター
みけCAT
記事: 6148
登録日時: 8年前
住所: 千葉県
連絡を取る:

Re: 複数のテキストファイルの扱い方

#8

投稿記事 by みけCAT » 4ヶ月前

YuO さんが書きました:
4ヶ月前
fopenだと,非標準動作ではあるものの伝統的にエラーの場合はerrnoに値を設定します。
C言語の標準には含まれていませんが、POSIXの標準には含まれているようです。
fopen
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

べけん
記事: 21
登録日時: 4ヶ月前

Re: 複数のテキストファイルの扱い方

#9

投稿記事 by べけん » 4ヶ月前

みけCAT さんが書きました:
4ヶ月前
printfをputsに置き換えずプログラムを動かしたところ、
自分の環境ではload errorが出ずに処理を行うことができました。
全角の数字や空白文字が混ざっているなど、処理対象のファイル名が間違っている可能性が考えられます。
3.txt以降の処理がうまくいかなかった原因についてですがおそらく一つ一つのファイルの分量が大きくchar arr[]の範囲が足らなかったのが影響していたようでした。しかし、テキストファイルは30近くあるのですがchar arr[]の[]内を100000といったかなり大きな値に変更したところ処理がされませんでした。おそらくchar arr[]の上限値に達したからだと思われますが、ほかの型で置き換えるなどしてこの上限以上にすることなどは可能でしょうか?

かずま

Re: 複数のテキストファイルの扱い方

#10

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

べけん さんが書きました:
4ヶ月前
3.txt以降の処理がうまくいかなかった原因についてですがおそらく一つ一つのファイルの分量が大きくchar arr[]の範囲が足らなかったのが影響していたようでした。
おそらくなどと言わずに、3.txt のサイズ、行数、行内の文字数の最大値を調べてください。
べけん さんが書きました:
4ヶ月前
しかし、テキストファイルは30近くあるのですがchar arr[]の[]内を100000といったかなり大きな値に変更したところ処理がされませんでした。
arr は main のローカル変数で自動変数なので、確保できるサイズが限られます。
static char arr[100000][500]; のように static を付けて静的に確保するか、
関数の外側でグローバル変数として宣言し、静的に確保するようにしてみてください。
べけん さんが書きました:
4ヶ月前
ほかの型で置き換えるなどしてこの上限以上にすることなどは可能でしょうか?
必要な領域を動的に確保すればよいでしょう。
ちょっと書いてみました。

コード:

#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;
}

べけん
記事: 21
登録日時: 4ヶ月前

Re: 複数のテキストファイルの扱い方

#11

投稿記事 by べけん » 4ヶ月前

static char arrにすることで無事解決しました!
ありがとうございます!

かずま

Re: 複数のテキストファイルの扱い方

#12

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

べけん さんが書きました:
4ヶ月前
static char arrにすることで無事解決しました!
グローバル変数にすることも試してみましたか?
領域の動的確保は理解したのですか?

3.txt のサイズ、行数、行内の文字数の最大値を教えてください。
エラーの原因をとことん追求しないと、これからも困りますよ。

かずま

Re: 複数のテキストファイルの扱い方

#13

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

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: 複数のテキストファイルの扱い方

#14

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

すみません。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);

返信

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