Как работать с файлами больше 2 ГБ - C (СИ)

Узнай цену своей работы

Формулировка задачи:

Всем доброго времени суток! Изучал работу с getopt_long и сделал программку для копирования файлов. Ну и дальше ради спортивного интереса начал допиливать её - сделал полоску вывода, оформил вывод размера в метрах/гигах, потом вынес вывод в отдельный поток, чтобы не тормозить копирование выводом... Но не в этом суть. Чтобы проверить вывод в гигах, надо было скопировать большой файл. Не нашёл ничего лучше образа IL-2 1946. А он, зараза, весит 3 гига с копейками. Запустил - а она мне выводит, мол, весит -1 Б и отстреливается. Не долго думая (знаю, что дурацкая идея) long, в котором я держал размер файла, переделал в unsigned long. Она мне сказала, что файл весит 4 гига ровно, затем скопировала примерно 2 гига и отстрелилась. Подключил мозг и выяснил, что ftell возвращает значение типа long, а в него помещается максимум 2147483647 (если считать это байтами, то в гигабайтах это будет 1,99999...). Отсюда

вопрос

: как в С полноценно работать с файлами больше 2 гигов? Полноценно - это в смысле не только читать-писать, но и корректно выполнять перемещение по файлу (ftell / fseek). Вот исходник в качестве иллюстрации проблемы:
Листинг программы
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. #include <getopt.h>
  4. #include <pthread.h>
  5. pthread_mutex_t in_mutex = PTHREAD_MUTEX_INITIALIZER;
  6. long in_progress = 0;
  7. long in_size = 0;
  8. pthread_mutex_t done_mutex = PTHREAD_MUTEX_INITIALIZER;
  9. char done = 0;
  10. void out_size( float size )
  11. {
  12. if( size < 1024.0f )
  13. printf( " %.0f B", size );
  14. else if( size < 1048576.0f )
  15. printf( " %.2f KB ", size / 1024.0f );
  16. else if( size < 1073741824.0f )
  17. printf( " %.2f MB ", size / 1048576.0f );
  18. else
  19. printf( " %.2f GB ", size / 1073741824.0f );
  20. }
  21. void progress_thread( void * p )
  22. {
  23. const unsigned short bar_resolution = 40;
  24. char buffer[ bar_resolution ];
  25. const unsigned delay = 100000;
  26. char l_done = 0;
  27. char spinner = '\\';
  28. do
  29. {
  30. /* ------- скопировать глобальные значения прогресса и размера файла в локальные переменные ------- */
  31. if( 0 != pthread_mutex_trylock( &in_mutex ) )
  32. {
  33. usleep( delay );
  34. continue;
  35. }
  36. long l_in_progress = in_progress;
  37. long l_in_size = in_size;
  38. pthread_mutex_unlock( &in_mutex );
  39. /* ------- проверить необходимость прерывания вывода ------- */
  40. pthread_mutex_lock( &done_mutex );
  41. if( done == 1 ) /* копирование завершено */
  42. {
  43. l_in_progress = l_in_size;
  44. l_done = 1;
  45. }
  46. else if ( done > 1 ) /* копирование прервано ошибкой */
  47. {
  48. pthread_mutex_unlock( &done_mutex );
  49. break;
  50. }
  51. pthread_mutex_unlock( &done_mutex );
  52. /* ------- вывести ------- */
  53. unsigned short progress = (float)l_in_progress / (float)l_in_size * 100.0f;
  54. unsigned short chars = (float)progress / 100.0f * (float)bar_resolution;
  55. printf( "\r%i%% [", progress );
  56. unsigned short i = 0;
  57. char *ptr = buffer;
  58. for( ; i < bar_resolution; i++, ptr++ )
  59. {
  60. if( i < chars )
  61. *ptr = '-';
  62. else if( i == chars )
  63. *ptr = spinner;
  64. else
  65. *ptr = ' ';
  66. }
  67. *ptr = 0;
  68. printf( "%s]", buffer );
  69. out_size( l_in_progress );
  70. putchar( '/' );
  71. out_size( l_in_size );
  72. printf( " " );
  73. /* ------- если необходимо прервать вывод, вывалиться из цикла ------- */
  74. if( l_done > 0 )
  75. break;
  76. if( spinner == '\\' ) spinner = '|';
  77. else if( spinner == '|' ) spinner = '/';
  78. else if( spinner == '/' ) spinner = '-';
  79. else spinner = '\\';
  80. usleep( delay );
  81. }
  82. while( 1 );
  83. pthread_exit( 0 );
  84. }
  85. inline void helpOut()
  86. {
  87. puts( "This program copies contents of one file into another\n"
  88. "\t-i, --input-file - specify INPUT file after this\n"
  89. "\t-o, --output-file - specify OUTPUT file after this\n"
  90. "\t-n, --no-output - do not produce output (except error messages)\n"
  91. "\t-h, --help - display this help message" );
  92. }
  93. const char * opt_str = "i:o:hn";
  94. const struct option opts[] =
  95. {
  96. { "input-file", required_argument, 0, 'i' },
  97. { "output-file", required_argument, 0, 'o' },
  98. { "help", no_argument, 0, 'h' },
  99. { "no-output", no_argument, 0, 'n' },
  100. { 0, no_argument, 0, 0 }
  101. };
  102. int main( int argc, char ** argv )
  103. {
  104. char * inFile = 0,
  105. * outFile = 0;
  106. char output = 1;
  107. int opt = getopt_long( argc, argv, opt_str, opts, 0 );
  108. while( opt != -1 )
  109. {
  110. switch( opt )
  111. {
  112. case 'i':
  113. inFile = optarg;
  114. break;
  115. case 'o':
  116. outFile = optarg;
  117. break;
  118. case 'h':
  119. helpOut();
  120. break;
  121. case 'n':
  122. output = 0;
  123. break;
  124. }
  125. opt = getopt_long( argc, argv, opt_str, opts, 0 );
  126. }
  127. FILE * f_in = fopen( inFile, "rb" );
  128. if( !f_in )
  129. {
  130. fprintf( stderr, "Error opening file \"%s\" for input: ", inFile );
  131. perror( 0 );
  132. return -1;
  133. }
  134. FILE * f_out = fopen( outFile, "wb" );
  135. if( !f_out )
  136. {
  137. fprintf( stderr, "Error opening file \"%s\" for output: ", outFile );
  138. perror( 0 );
  139. fclose( f_in );
  140. return -1;
  141. }
  142. /* узнать размер файла */
  143. fseek( f_in, 0, SEEK_END );
  144. in_size = ftell( f_in );
  145. fseek( f_in, 0, SEEK_SET );
  146. pthread_t id;
  147. if( output )
  148. {
  149. puts( "Copying:" );
  150. pthread_create( &id, 0, progress_thread, 0 );
  151. }
  152. const unsigned block_size = 4096;
  153. char buffer[ block_size ];
  154. while( in_progress < in_size )
  155. {
  156. long int size = in_size - in_progress > block_size ? block_size : in_size - in_progress;
  157. if( size != fread( buffer, 1, size, f_in ))
  158. {
  159. perror( "\nCould not read input file" );
  160. if( output ) pthread_mutex_lock( &done_mutex );
  161. done = 2; /* прервать поток вывода с ошибкой */
  162. if( output ) pthread_mutex_unlock( &done_mutex );
  163. break;
  164. }
  165. if( size != fwrite( buffer, 1, size, f_out ) )
  166. {
  167. perror( "\nCould not write to output file" );
  168. if( output ) pthread_mutex_lock( &done_mutex );
  169. done = 2; /* прервать поток вывода с ошибкой */
  170. if( output ) pthread_mutex_unlock( &done_mutex );
  171. break;
  172. }
  173. if( output ) pthread_mutex_lock( &in_mutex );
  174. in_progress = ftell( f_in );
  175. if( output ) pthread_mutex_unlock( &in_mutex );
  176. }
  177. if( output && done == 0 )
  178. {
  179. pthread_mutex_lock( &done_mutex );
  180. done = 1; /* прервать поток вывода */
  181. pthread_mutex_unlock( &done_mutex );
  182. }
  183. fclose( f_out );
  184. fclose( f_in );
  185. if( output )
  186. {
  187. pthread_join( id, 0 );
  188. puts( "\nDone." );
  189. }
  190. if( done == 2 ) /* в случае ошибки во время копирования */
  191. return 1;
  192. return 0;
  193. }
Запускал под XP SP2.

Решение задачи: «Как работать с файлами больше 2 ГБ»

textual
Листинг программы
  1. #include <iostream>
  2. #include <wx/wx.h>
  3. #include <wx/file.h>
  4. #include <wx/ffile.h>
  5. #include <wx/filename.h>
  6.  
  7. int main(int argc, char* argv[])
  8. {
  9.     setlocale(LC_ALL, "");
  10.     wxInitialize(argc, argv);
  11. #ifdef wxHAS_LARGE_FFILES
  12.     std::cout << "wxHAS_LARGE_FFILES" << std::endl;
  13. #else // !wxHAS_LARGE_FFILES
  14.     std::cout << "No Large files support with wxFFile" << std::endl;
  15. #endif // wxHAS_LARGE_FFILES
  16. #ifdef wxHAS_LARGE_FILES
  17.     std::cout << "wxHAS_LARGE_FILES" << std::endl;
  18. #else // !wxHAS_LARGE_FILES
  19.     std::cout << "No Large files support with wxFile" << std::endl;
  20. #endif // wxHAS_LARGE_FILES
  21.  
  22.     wxFileName filename(wxT("test.dat"));
  23.  
  24.     wxString str;
  25.     wxFileOffset pos;
  26.     if (filename.FileExists())
  27.     {
  28.         std::cout << "File size: "
  29.             << filename.GetSize().ToString().mb_str()
  30.             << std::endl;
  31. #ifdef wxHAS_LARGE_FFILES
  32.         // Файлы с буферизацией (обёртка над FILE)
  33.         wxFFile ffile(filename.GetFullPath());
  34.         ffile.SeekEnd();    
  35.         pos = ffile.Tell();
  36.         str.Printf(wxT("wxFFile end pos: %") wxFileOffsetFmtSpec wxT("d"), pos);
  37.         std::cout << str.mb_str() << std::endl;
  38.         ffile.Close();
  39. #endif // wxHAS_LARGE_FFILES
  40.    
  41. #ifdef wxHAS_LARGE_FILES
  42.         // "Сырые" файлы
  43.         wxFile file(filename.GetFullPath());
  44.         file.SeekEnd();
  45.         pos = file.Tell();
  46.         str.Printf(wxT("wxFile end pos: %") wxFileOffsetFmtSpec wxT("d"), pos);
  47.         std::cout << str.mb_str() << std::endl;
  48.         file.Close();
  49. #endif // wxHAS_LARGE_FILES
  50.     }
  51.     else
  52.     {
  53.         std::cout << "The file does not exist" <<std::endl;
  54.     }  
  55.  
  56.     wxUninitialize();
  57.     return 0;
  58. }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

11   голосов , оценка 4.091 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут