123

C でファイルを開き、その内容を文字列 (char*、char[] など) に読み込む最も簡単な方法 (エラーが発生しにくく、コードの行数が少なく、解釈したい) は何ですか?

4

12 に答える 12

167

私はバッファ全体を生のメモリ チャンクとしてメモリにロードし、自分で解析を行う傾向があります。そうすれば、標準ライブラリが複数のプラットフォームで何をするかを最適に制御できます。

これは私がこれに使用するスタブです。また、fseek、ftell、および fread のエラー コードを確認することもできます。(わかりやすくするために省略)。

char * buffer = 0;
long length;
FILE * f = fopen (filename, "rb");

if (f)
{
  fseek (f, 0, SEEK_END);
  length = ftell (f);
  fseek (f, 0, SEEK_SET);
  buffer = malloc (length);
  if (buffer)
  {
    fread (buffer, 1, length, f);
  }
  fclose (f);
}

if (buffer)
{
  // start to process your data / extract strings here...
}
于 2008-10-06T14:37:00.520 に答える
34

残念ながら OS に大きく依存するもう 1 つの解決策は、ファイルのメモリ マッピングです。一般に、アプリケーション ビューとオペレーティング システムのファイル キャッシュが実際に物理メモリを共有できるため、読み取りのパフォーマンスが向上し、メモリ使用量が削減されます。

POSIX コードは次のようになります。

int fd = open("filename", O_RDONLY);
int len = lseek(fd, 0, SEEK_END);
void *data = mmap(0, len, PROT_READ, MAP_PRIVATE, fd, 0);

一方、Windows はもう少しトリッキーです。残念ながら、目の前にテスト用のコンパイラはありませんが、機能は and によって提供されCreateFileMapping()ますMapViewOfFile()

于 2008-10-06T15:37:28.153 に答える
17

「内容を文字列に読み込む」とは、ファイルにコード0の文字が含まれていないことを意味する場合は、getdelim()関数を使用して、メモリのブロックを受け入れ、必要に応じて再割り当てするか、バッファ全体を次のように割り当てることもできます。指定された区切り文字またはファイルの終わりに遭遇するまで、ファイルを読み込みます。ファイル全体を読み取るには、区切り文字として「\0」を渡すだけです。

この関数は、GNU Cライブラリ(http://www.gnu.org/software/libc/manual/html_mono/libc.html#index-getdelim-994 )で利用できます。

サンプルコードは次のように単純に見えるかもしれません

char* buffer = NULL;
size_t len;
ssize_t bytes_read = getdelim( &buffer, &len, '\0', fp);
if ( bytes_read != -1) {
  /* Success, now the entire file is in the buffer */
于 2008-10-06T15:24:23.233 に答える
8

stdin やパイプなどの特殊なファイルを読み取る場合、fstat を使用して事前にファイル サイズを取得することはできません。また、バイナリ ファイルを読み取る場合、「\0」文字が埋め込まれているため、fgets は文字列サイズ情報を失います。ファイルを読み取る最良の方法は、read と realloc を使用することです。

#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

int main () {
    char buf[4096];
    ssize_t n;
    char *str = NULL;
    size_t len = 0;
    while (n = read(STDIN_FILENO, buf, sizeof buf)) {
        if (n < 0) {
            if (errno == EAGAIN)
                continue;
            perror("read");
            break;
        }
        str = realloc(str, len + n + 1);
        memcpy(str + len, buf, n);
        len += n;
        str[len] = '\0';
    }
    printf("%.*s\n", len, str);
    return 0;
}
于 2013-11-24T19:40:34.630 に答える
5

ファイルがテキストで、テキストを 1 行ずつ取得する場合、最も簡単な方法は fgets() を使用することです。

char buffer[100];
FILE *fp = fopen("filename", "r");                 // do not use "rb"
while (fgets(buffer, sizeof(buffer), fp)) {
... do something
}
fclose(fp);
于 2008-10-08T21:02:07.590 に答える
5

注:これは、上記の受け入れられた回答の修正です。

これを行う方法は次のとおりです。エラーチェックを完了します。

ファイルが 1 GiB を超えたときに終了するサイズ チェッカーを追加しました。これを行ったのは、プログラムがファイル全体を文字列に入れ、RAM を使いすぎてコンピューターをクラッシュさせる可能性があるためです。ただし、それを気にしない場合は、コードから削除できます。

#include <stdio.h>
#include <stdlib.h>

#define FILE_OK 0
#define FILE_NOT_EXIST 1
#define FILE_TOO_LARGE 2
#define FILE_READ_ERROR 3

char * c_read_file(const char * f_name, int * err, size_t * f_size) {
    char * buffer;
    size_t length;
    FILE * f = fopen(f_name, "rb");
    size_t read_length;
    
    if (f) {
        fseek(f, 0, SEEK_END);
        length = ftell(f);
        fseek(f, 0, SEEK_SET);
        
        // 1 GiB; best not to load a whole large file in one string
        if (length > 1073741824) {
            *err = FILE_TOO_LARGE;
            
            return NULL;
        }
        
        buffer = (char *)malloc(length + 1);
        
        if (length) {
            read_length = fread(buffer, 1, length, f);
            
            if (length != read_length) {
                 free(buffer);
                 *err = FILE_READ_ERROR;

                 return NULL;
            }
        }
        
        fclose(f);
        
        *err = FILE_OK;
        buffer[length] = '\0';
        *f_size = length;
    }
    else {
        *err = FILE_NOT_EXIST;
        
        return NULL;
    }
    
    return buffer;
}

そして、エラーをチェックするには:

int err;
size_t f_size;
char * f_data;

f_data = c_read_file("test.txt", &err, &f_size);

if (err) {
    // process error
}
else {
    // process data
    free(f_data);
}
于 2019-01-06T00:48:52.780 に答える
3

を使用している場合は、 g_file_get_contentsglibを使用できます。

gchar *contents;
GError *err = NULL;

g_file_get_contents ("foo.txt", &contents, NULL, &err);
g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
if (err != NULL)
  {
    // Report error to user, and free error
    g_assert (contents == NULL);
    fprintf (stderr, "Unable to read file: %s\n", err->message);
    g_error_free (err);
  }
else
  {
    // Use file contents
    g_assert (contents != NULL);
  }
}
于 2016-10-07T10:24:20.787 に答える
1
// Assumes the file exists and will seg. fault otherwise.
const GLchar *load_shader_source(char *filename) {
  FILE *file = fopen(filename, "r");             // open 
  fseek(file, 0L, SEEK_END);                     // find the end
  size_t size = ftell(file);                     // get the size in bytes
  GLchar *shaderSource = calloc(1, size);        // allocate enough bytes
  rewind(file);                                  // go back to file beginning
  fread(shaderSource, size, sizeof(char), file); // read each char into ourblock
  fclose(file);                                  // close the stream
  return shaderSource;
}

null に対して何もチェックされないため、これは非常に大雑把な解決策です。

于 2016-05-15T17:49:49.693 に答える