fread — Бинарно-безопасное чтение файла


Функции fread() и fwrite()

Для чтения и записи данных, тип которых может занимать более 1 байта, в файловой системе языка С имеется две функции: fread() и fwrite() . Эти функции позволяют читать и записывать блоки данных любого типа. Их прототипы следующие:

Для fread() буфер — это указатель на область памяти, в которую будут прочитаны данные из файла. А для fwrite() буфер — это указатель на данные, которые будут записаны в файл. Значение счетчик определяет, сколько считывается или записывается элементов данных, причем длина каждого элемента в байтах равна колич_байт . (Вспомните, что тип size_t определяется как одна из разновидностей целого типа без знака.) И, наконец, уф — это указатель файла, то есть на уже открытый поток.

Функция fread() возвращает количество прочитанных элементов. Если достигнут конец файла или произошла ошибка, то возвращаемое значение может быть меньше, чем счетчик. А функция fwrite() возвращает количество записанных элементов. Если ошибка не произошла, то возвращаемый результат будет равен значению счетчик.

Использование fread() и fwrite()

Как только файл открыт для работы с двоичными данными, fread() и fwrite() соответственно могут читать и записывать информацию любого типа. Например, следующая программа записывает в дисковый файл данные типов double , int и long , a затем читает эти данные из того же файла. Обратите внимание, как в этой программе при определении длины каждого типа данных используется функция sizeof() .

Как видно из этой программы, в качестве буфера можно использовать (и часто именно так и делают) просто память, в которой размещена переменная. В этой простой программе значения, возвращаемые функциями fread() и fwrite() , игнорируются. Однако на практике эти значения необходимо проверять, чтобы обнаружить ошибки.

Одним из самых полезных применений функций fread() и fwrite() является чтение и запись данных пользовательских типов, особенно структур. Например, если определена структура

то следующий оператор записывает содержимое cust в файл, на который указывает fp :

Пример со списком рассылки

Чтобы показать, как можно легко записывать большие объемы данных, пользуясь функциями fread() и fwrite() , мы переделаем программу работы со списком рассылки, с которой впервые встретились в главе 7. Усовершенствованная версия сможет сохранять адреса в файле. Как и раньше, адреса будут храниться в массиве структур следующего типа:

Значение MAX определяет максимальное количество адресов, которое может быть в списке.

При выполнении программы поле name каждой структуры инициализируется пустым указателем ( NULL ). В программе свободной считается та структура, поле name которой содержит строку нулевой длины, т.е. имя адресата представляет собой пустую строку.

Далее приведены функции save() и load() , которые используются соответственно для сохранения и загрузки базы данных (списка рассылки). Обратите внимание, насколько кратко удалось закодировать каждую из функций, а ведь эта краткость достигнута благодаря мощи fread() и fwrite() ! И еше обратите внимание на то, как эти функции проверяют значения, возвращаемые функциями fread() и fwrite() , чтобы обнаружить таким образом возможные ошибки.

Обе функции, save() и load() , подтверждают (или не подтверждают) успешность выполнения функциями fread() и fwrite() операций с файлом, проверяя значения, возвращаемые функциями fread() и fwrite() . Кроме того, функция load() явно проверяет, не достигнут ли конец файла. Делает она это с помощью вызова функции feof() . Это приходится делать потому, что fread() и в случае ошибки, и при достижении конца файла возвращает одно и то же значение.

fread

В языке C++ иногда требуется считать из бинарного файла достаточно крупные объемы данных, при этом как-то классифицировав и разделив на переменные. Для этого прекрасно подходит одна из функций библиотеки cstdio – fread. Эта же функция есть и в более старой библиотеке stdio.h.

Функция выглядит так:

где каждый из параметров сильно влияет на получаемый результат:

  • void * ptrvoid — указатель на переменную, в которую мы считываем данные из файла;
  • size_t razm — размер одного считываемого элемента в байтах, чтобы не считать размер часто пишут что-то похожее на sizeof(int) или sizeof(пользовательский тип);
  • size_t count — количество считываемых элементов;
  • FILE *filestream — файловая переменная того файла, из которого мы читаем. Так же после выполнения функция возвращает количество успешно считанных сущностей, что можно использовать для отслеживания сбоев. Рассмотрим конкретный пример:

Fread — Бинарно-безопасное чтение файла

(PHP 3, PHP 4 , PHP 5)

fread — Бинарно-безопасное чтение файла

Описание string fread ( resource handle, int length )

fread() читает до length байтов из файлового указателя handle . Чтение останавливается при достижении length байтов, EOF (конца файла) или (для сетевых потоков) когда пакет становится доступным, что бы не произошло первым.

На системах, которые различают бинарные и текстовые файлы (к примеру Windows), файл должен быть открыт с использованием буквы ‘b’ в параметре mode функции fopen() .

Внимание

Following code which was given as official example can lead to infinite loop.
In case of running from command line and there is no Internet connection, fopen will fail by script timeout, however after that «!feof($handle)» will never be true.

The result will be script displaying infinite warnings and taking 10-20% cpu and it will not stop unless killed.

= fopen ( «http://www.example.com/» , «r» );
$contents = » ;
while (! feof ( $handle )) <
$contents .= fread ( $handle , 8192 );
>
fclose ( $handle );
?>

I belive correct example should be:

= fopen ( «http://www.example.com/» , «r» );
$contents = » ;
if( $handle )
<
while (! feof ( $handle )) <
$contents .= fread ( $handle , 8192 );
>
fclose ( $handle );
>
?>

Several of these examples use a Content-Disposition header to force the browser to save a file but then they specify the file name without quotes. This will cause problems for some browsers (Mozilla Fire Fox) if the file name contains a space. You must put quotes around the name if you want to work reliably for all files in all browsers.
( «Content-Disposition: attachment; filename=$theFileName» ); // bad

header ( «Content-Disposition: attachment; filename= \» $theFileName \» » ); // good

For download the big files (more than 8MB), you must used ob_flush() because the function flush empty the Apache memory and not PHP memory.
And the max size of PHP memory is 8MB, but ob_flush is able to empty the PHP memory.

header(‘Content-Type: application/force-download’);
header («Content-Length: » . filesize($file));
header («Content-Disposition: attachment; filename=$theFileName»);

$fd = fopen($file, «r»);
while(!feof($fd))
<
echo fread($fd, 4096);
ob_flush();

Just a note for anybody trying to implement a php handled download script —

We spent a long time trying to figure out why our code was eating system resources on large files.. Eventually we managed to trace it to output buffering that was being started on every page via an include.. (It was attempting to buffer the entire 600 Megs or whatever size *before* sending data to the client) if you have this problem you may want to check that first and either not start buffering or close that in the usual way :)

Hope that prevents somebody spending hours trying to fix an obscure issue.

I was trying to implement resume support in download script, and i have finnaly succeded. here is the script:

function dl_file_resume ( $file )<

//First, see if the file exists
if (! is_file ( $file )) < die( "404 File not found!» ); >

//Gather relevent info about file
$len = filesize ( $file );
$filename = basename ( $file );
$file_extension = strtolower ( substr ( strrchr ( $filename , «.» ), 1 ));

//This will set the Content-Type to the appropriate setting for the file
switch( $file_extension ) <
case «exe» : $ctype = «application/octet-stream» ; break;
case «zip» : $ctype = «application/zip» ; break;
case «mp3» : $ctype = «audio/mpeg» ; break;
case «mpg» : $ctype = «video/mpeg» ; break;
case «avi» : $ctype = «video/x-msvideo» ; break;

//The following are for extensions that shouldn’t be downloaded (sensitive stuff, like php files)
case «php» :
case «htm» :
case «html» :
case «txt» : die( «Cannot be used for » . $file_extension . » files!» ); break;

default: $ctype = «application/force-download» ;
>

//Begin writing headers
header ( «Pragma: public» );
header ( «Expires: 0» );
header ( «Cache-Control:» );
header ( «Cache-Control: public» );
header ( «Content-Description: File Transfer» );

//Use the switch-generated Content-Type
header ( «Content-Type: $ctype» );
$filespaces = str_replace ( «_» , » » , $filename );

//if your filename contains underscores, you can replace them with spaces
$header = ‘Content-Disposition: attachment; filename=’ . $filespaces . ‘;’ ;
header ( $header );
header ( «Content-Transfer-Encoding: binary» );

$size = filesize ( $file );
//check if http_range is sent by browser (or download manager)
if(isset( $_ENV [ ‘HTTP_RANGE’ ])) <
list( $a , $range )= explode ( «=» , $_ENV [ ‘HTTP_RANGE’ ]);
//if yes, download missing part
str_replace ( $range , «-» , $range );
$size2 = $size — 1 ;
header ( «Content-Range: $range$size2/$size» );
$new_length = $size2 — $range ;
header ( «Content-Length: $new_length» );
/if not , download whole file
> else <
$size2 = $size — 1 ;
header ( «Content-Range: bytes 0-$size2/$size» );
header ( «Content-Length: » . $size2 );
>
//open the file
$fp = fopen ( «$file» , «r» );
//seek to start of missing part
fseek ( $fp , $range );
//start buffered download
while(! feof ( $fp ))
<
//reset time limit for big files
set_time_limit ();
print( fread ( $fp , 1024 * 8 ));
flush ();
>
fclose ( $fp );

>
?>

EXAMPLE
( «somefile.mp3» );
?>

please write if you find any errors, i have tested this only with mp3 files, but others should be fine

To make the effects of the latest PHP version changes of the fread function even more explicit: the new size limitation of fread -regardless of the filesize one specifies, in the example below 1024 * 1024- means that if one was simply reading the contents of a text file from a dynamic URL like so:


Error: unable to load URL file into $buffer. Process aborted.

» );
exit();
>
$sp = fread ( $buffer , 1024 * 1024 );
fclose ( $buffer );
highlight_string ( $sp );
?>

one should from now on use the file_get_contents function, as shown below, to avoid one’s text being truncated forcibly.

Error: unable to load URL file into $dp. Process aborted.

» );
exit();
>
$sp = file_get_contents ( $dp );
highlight_string ( $sp );
?>

I thought it couldn’t hurt to clarify this detail in order to save time for anyone else who is in the same situation as I was tonight when my ISP abruptly upgraded to the latest version of PHP. :(

Thank you to every previous contributor to this topic.

Here’s a function for sending a file to the client — it may look more complicated than necessary, but has a number of advantages over simpler file sending functions:

— Works with large files, and uses only an 8KB buffer per transfer.

— Stops transferring if the client is disconnected (unlike many scripts, that continue to read and buffer the entire file, wasting valuable resources) but does not halt the script

— Returns TRUE if transfer was completed, or FALSE if the client was disconnected before completing the download — you’ll often need this, so you can log downloads correctly.

— Sends a number of headers, including ones that ensure it’s cached for a maximum of 2 hours on any browser/proxy, and «Content-Length» which most people seem to forget.

(tested on Linux (Apache) and Windows (IIS5/6) under PHP4.3.x)

Note that the folder from which protected files will be pulled, is set as a constant in this function (/protected) . Now here’s the function:

function send_file ( $name ) <
ob_end_clean ();
$path = «protected/» . $name ;
if (! is_file ( $path ) or connection_status ()!= 0 ) return( FALSE );
header ( «Cache-Control: no-store, no-cache, must-revalidate» );
header ( «Cache-Control: post-check=0, pre-check=0» , false );
header ( «Pragma: no-cache» );
header ( «Expires: » . gmdate ( «D, d M Y H:i:s» , mktime ( date ( «H» )+ 2 , date ( «i» ), date ( «s» ), date ( «m» ), date ( «d» ), date ( «Y» ))). » GMT» );
header ( «Last-Modified: » . gmdate ( «D, d M Y H:i:s» ). » GMT» );
header ( «Content-Type: application/octet-stream» );
header ( «Content-Length: » .(string)( filesize ( $path )));
header ( «Content-Disposition: inline; filename=$name» );
header ( «Content-Transfer-Encoding: binary\n» );
if ( $file = fopen ( $path , ‘rb’ )) <
while(! feof ( $file ) and ( connection_status ()== 0 )) <
print( fread ( $file , 1024 * 8 ));
flush ();
>
fclose ( $file );
>
return(( connection_status ()== 0 ) and ! connection_aborted ());
>
?>

And here’s an example of using the function:

if (! send_file ( «platinumdemo.zip» )) <
die ( «file transfer failed» );
// either the file transfer was incomplete
// or the file was not found
> else <
// the download was a success
// log, or do whatever else
>
?>

Regards,
Rasmus Schultz

using the ternary operator as follows seems to be the neatest way of eliminating the 0 length warning (discussed above).

$content = filesize($file)?fread($handle, filesize($file)):»»;

Somewhere between 4.2.3 and 4.3.9, the behaviour of fread() was changed slightly.

When you ask to fread() 0 bytes of data, it spits out a warning (IMO for no good reason. I think reading 0 bytes is perfectly valid, if not very useful.)

Consequently, to write warning-free code using fread, you’d have to take code like this:

and replace it with this:

$content=»;
$length=filesize($myfile);
if($length) <
$content = fread($fd, $length);
>

. or this, depending on your taste:

$length=filesize($myfile);
if($length) <
$content = fread($fd, $length);
> else <
$content=»;
>

(I’m aware that there are much better ways to read in a whole file at once. I’m just fixing up someone else’s code after a server switch and ran across this stupid warning.)

If, like me, you’re in the habit of using fopen(«http://. «) and fread for pulling fairly large remote files, you may find that the upgrade to PHP5 (5.0.2 on Win2000/IIS5) causes fread to top out at about 8035 bytes. PHP5 RC2 with identical php.ini settings did not exhibit this behaviour (I was using this for testing). Irritating for me because I was using simple_xml_load to load the file contents as XML, and the problem initially appeared to be that function.

Solution — swap over to file_get_contents or use the loop suggested on the documentation above (see Warning).

Problem: mime attachments sending as blank or almost completely blank documents (all data is lost)

Explanation: After a couple days of trying to mime pdf attachments without losing all data, I finally came across this function in some obsolete obscure post:

This is set to on by default in the machine, and it causes fread() and/or base64_encode() (both used in most mime examples I’ve seen) to read or encrypt binary without slashes for special characters. This causes sent files to process incorrectly, breaking, thus truncating most of the data in the file.

Fix: pass 0 to this function and it will do a one time turn off while your code executes.

example:
( 0 );
?>

This can also been turned off in the php.ini file, but I’m not sure what uses that setting or what the consequences might be.

After using the suggested function from Rasmus Schultz : mindplay(at)mindplay(dot)dk, I’ve just noticed that people trying to download big files with a slow connection would get download stopped after exactly 60seconds -> the max execution time set with php.ini.
I suggest using a bigger buffer (1024×1024), or maybe resetting the time limit within the ‘while’ cicle with:
set_time_limit(0);

The cicle would go like this:

while(!feof($file) and (connection_status()==0)) <
print(fread($file, 1024*1024));
set_time_limit(0);
flush();
>

As of PHP 5.0.0 and PHP 4.3.8, fread($stream, 2048) will only grab 1 packet worth of data from the buffer in a TCP/IP or UDP stream.

Note: 2048 is the suggested size to make sure you get all of one packet, any size larger than that will still have the same result

The following function retrieves a line in a file, regardless of its size, so you won’t get an error if the file’s size is beyond php’s allowed memory limit (the string has to be below however), which is something i was needing for accessing a big log file generated by a webhost. Indexes start at 1 (so $line = 1 means the first line unlike arrays). If the file is small, it would be better to use «file()» however.

function strpos_count ( $haystack , $needle , $i = 0 ) <
while ( strpos ( $haystack , $needle ) !== false ) < $haystack = substr ( $haystack , ( strpos ( $haystack , $needle ) + 1 )); $i ++;>
return $i ;
>
function getLine ( $file , $line = 1 ) <
$occurence = 0 ;
$contents = » ;
$startPos = — 1 ;
if (! file_exists ( $file )) return » ;
$fp = @ fopen ( $file , «rb» );
if (! $fp ) return » ;
while (!@ feof ( $fp )) <
$str = @ fread ( $fp , 1024 );
$number_of_occurences = strpos_count ( $str , «\n» );
if ( $number_of_occurences == 0 ) >
else <
$lastPos = 0 ;
for ( $i = 0 ; $i $number_of_occurences ; $i ++) <
$pos = strpos ( $str , «\n» , $lastPos );
$occurence ++;
if ( $occurence == $line ) <
$startPos = $pos ;
if ( $i == $number_of_occurences — 1 ) < $contents = substr ( $str , $startPos + 1 );>
> elseif ( $occurence == $line + 1 ) <
if ( $i == 0 ) < $contents .= substr ( $str , 0 , $pos );>else < $contents = substr ( $str , $startPos , $pos - $startPos );>
$occurence = 0 ;
break;
>
$lastPos = $pos + 1 ;
>
>
>
@ fclose ( $fp );
return $contents ;
>
?>

fread also works for fsockopen’s that are open-ended (no feof) if you know how the last packet for a particular set of data should end. For example, if you sent a command to an nntp server, the reply from the server would end with a dot and a carriage return/linefeed. The connection still stays open for more commands, but doing it this way is more efficient than doing line-by-line fgets until you get to the end of the reply.

if(( $res = nntp_cmd ( $conn , «BODY $msgid» , 222 ))=== false ) <
continue;
>else <
$contents = » ;
while( 1 ) <
$packet = fread ( $conn , 8192 );
$contents .= $packet ;
if( substr ( $packet ,- 3 )== «.\r\n» )break;
>
// do something with $contents
>
?>

Two quick notes on download prompting.
First, the following line:

( «Cache-Control: no-cache, must-revalidate» );
?>

causes IE6 to prompt you to download the script instead of the output and will fail to connect. Take out that header and everything works perfectly.

Pragma: no-cache doesn’t cause a problem.

Second, Mozilla tries to add .php to the download file name if content-type is application. Changing the content type to the more specific MIME type (such as audio/mpeg) fixes that but causes IE to try its plugins (such as Quicktime).

The fix I found for that to specify attachment instead of inline. Here’s my code: a prompted, small buffer MP3 download:

function downloadMP3 ( $fileDir , $fileName ) <
$completeFilePath = $fileDir . ‘/’ . $fileName ;
header ( ‘Pragma: no-cache’ );
header ( «Content-type: audio/mpeg\nContent-Disposition: attachment; filename=\»» . $fileName . «\»\nContent-length: » .(string)( filesize ( $completeFilePath )));
$fd = fopen ( $completeFilePath , ‘rb’ );
while(! feof ( $fd )) <
print( fread ( $fd , 4096 ));
flush ();
>
>
?>

Simple script to limit browser download speed using fread function.

= «test.mp3» ; // file to be send to the client
$speed = 8.5 ; // 8,5 kb/s download rate limit

if( file_exists ( $file ) && is_file ( $file )) <

header ( «Cache-control: private» );
header ( «Content-Type: application/octet-stream» );
header ( «Content-Length: » . filesize ( $file ));
header ( «Content-Disposition: filename=$file» . «%20» );

$fd = fopen ( $file , «r» );
while(! feof ( $fd )) <
echo fread ( $fd , round ( $speed * 1024 ));
flush ();
sleep ( 1 );
>
fclose ( $fd );

I spent a while trying to get this to work so I thought I’d share.

Here’s how to read a remote binary file using fread.


if( $fp ) <
while(! feof ( $fp )) <
$img = $img . fread ( $fp , 1024 );
>
>
?>

This will read the contents of the file into the var $img 1024 bytes at a time. I used that number because it seemed safe, but you can increment it all you want I guess.

I don’t know if everyone but me gets this, but I thought I’d share since I didn’t see anything like it out there.

I wrote a simple function for grabbing binary files from the web.

function wwwcopy ( $file , $nfile )
<
$fp = @ fopen ( $file , «rb» );
while(! feof ( $fp ))
<
$cont .= fread ( $fp , 1024 );
>
fclose ( $fp );

$fp2 = @ fopen ( $nfile , «w» );
fwrite ( $fp2 , $cont );
fclose ( $fp2 );
>
?>

Fread is binary-safe IF AND ONLY IF you don’t use magic-quotes. If you do, all null bytes will become \0, and you might get surprising results when unpacking.

That is, you would do something like

and something like

( get_magic_quotes_gpc ()) after .
?>

And, after fread, an unpack would be needed, of course. Surprisingly, pack(), however, does not work quite like in Perl (or perhaps I’m just missing something here) — you can’t pack an array directly, but instead you’ll have to pack each element seperately to the string:

foreach ( $data as $dec ) <
$data_output .= pack ( «C*» , $dec );
>
?>

For reading from a specified point in the file, use:

Бинарные файлы

Бинарные файлы

Т екстовые файлы хранят данные в виде текста (sic!). Это значит, что если, например, мы записываем целое число 12345678 в файл, то записывается 8 символов, а это 8 байт данных, несмотря на то, что число помещается в целый тип. Кроме того, вывод и ввод данных является форматированным, то есть каждый раз, когда мы считываем число из файла или записываем в файл происходит трансформация числа в строку или обратно. Это затратные операции, которых можно избежать.

Текстовые файлы позволяют хранить информацию в виде, понятном для человека. Можно, однако, хранить данные непосредственно в бинарном виде. Для этих целей используются бинарные файлы.

Выполните программу и посмотрите содержимое файла output.bin. Число, которое ввёл пользователь записывается в файл непосредственно в бинарном виде. Можете открыть файл в любом редакторе, поддерживающем представление в шестнадцатеричном виде (Total Commander, Far) и убедиться в этом.

Запись в файл осуществляется с помощью функции

Функция возвращает число удачно записанных элементов. В качестве аргументов принимает указатель на массив, размер одного элемента, число элементов и указатель на файловый поток. Вместо массив, конечно, может быть передан любой объект.

Запись в бинарный файл объекта похожа на его отображение: берутся данные из оперативной памяти и пишутся как есть. Для считывания используется функция fread

Функция возвращает число удачно прочитанных элементов, которые помещаются по адресу ptr. Всего считывается count элементов по size байт. Давайте теперь считаем наше число обратно в переменную.

fseek

Одной из важных функций для работы с бинарными файлами является функция fseek

Эта функция устанавливает указатель позиции, ассоциированный с потоком, на новое положение. Индикатор позиции указывает, на каком месте в файле мы остановились. Когда мы открываем файл, позиция равна 0. Каждый раз, записывая байт данных, указатель позиции сдвигается на единицу вперёд.
fseek принимает в качестве аргументов указатель на поток и сдвиг в offset байт относительно origin. origin может принимать три значения

  • SEEK_SET — начало файла
  • SEEK_CUR — текущее положение файла
  • SEEK_END — конец файла. К сожалению, стандартом не определено, что такое конец файла, поэтому полагаться на эту функцию нельзя.

В случае удачной работы функция возвращает 0.

Дополним наш старый пример: запишем число, затем сдвинемся указатель на начало файла и прочитаем его.

Вместо этого можно также использовать функцию rewind, которая перемещает индикатор позиции в начало.

В си определён специальный тип fpos_t, который используется для хранения позиции индикатора позиции в файле.
Функция

используется для того, чтобы назначить переменной pos текущее положение. Функция

используется для перевода указателя в позицию, которая хранится в переменной pos. Обе функции в случае удачного завершения возвращают ноль.

возвращает текущее положение индикатора относительно начала файла. Для бинарных файлов — это число байт, для текстовых не определено (если текстовый файл состоит из однобайтовых символов, то также число байт).

Рассмотрим пример: пользователь вводит числа. Первые 4 байта файла: целое, которое обозначает, сколько чисел было введено. После того, как пользователь прекращает вводить числа, мы перемещаемся в начало файла и записываем туда число введённых элементов.

Вторая программа сначала считывает количество записанных чисел, а потом считывает и выводит числа по порядку.

Примеры

1. Имеется бинарный файл размером 10*sizeof(int) байт. Пользователь вводит номер ячейки, после чего в неё записывает число. После каждой операции выводятся все числа. Сначала пытаемся открыть файл в режиме чтения и записи. Если это не удаётся, то пробуем создать файл, если удаётся создать файл, то повторяем попытку открыть файл для чтения и записи.

2. Пишем слова в бинарный файл. Формат такой — сначало число букв, потом само слово без нулевого символа. Ели длина слова равна нулю, то больше слов нет. Сначала запрашиваем слова у пользователя, потом считываем обратно.

3. Задача — считать данные из текстового файла и записать их в бинарный. Для решения зачи создадим функцию обёртку. Она будет принимать имя файла, режим доступа, функцию, которую необходимо выполнить, если файл был удачно открыт и аргументы этой функции. Так как аргументов может быть много и они могут быть разного типа, то их можно передавать в качестве указателя на структуру. После выполнения функции файл закрывается. Таким образом, нет необходимости думать об освобождении ресурсов.

4. Функция saveInt32Array позволяет сохранить массив типа int32_t в файл. Обратная ей loadInt32Array считывает массив обратно. Функция loadInt32Array сначала инициализирует переданный ей массив, поэтому мы должны передавать указатель на указатель; кроме того, она записывает считанный размер массива в переданный параметр size, из-за чего он передаётся как указатель.

5. Создание таблицы поиска. Для ускорения работы программы вместо вычисления функции можно произвести сначала вычисление значений функции на интервале с определённой точностью, после чего брать значения уже из таблицы. Программа сначала производит табулирование функции с заданными параметрами и сохраняет его в файл, затем подгружает предвычисленный массив, который уже используется для определения значений. В этой программе все функции возвращают переменную типа Result, которая хранит номер ошибки. Если функция отработала без проблем, то она возвращает Ok (0).

6. У нас имеются две структуры. Первая PersonKey хранит логин, пароль, id пользователя и поле offset. Вторая структура PersonInfo хранит имя и фамилию пользователя и его возраст. Первые структуры записываются в бинарный файл keys.bin, вторые структуры в бинарный файл values.bin. Поле offset определяет положение соответствующей информации о пользователе во втором файле. Таким образом, получив PersonKey из первого файла, по полю offset можно извлечь из второго файла связанную с данным ключом информацию.

Зачем так делать? Это выгодно в том случае, если структура PersonInfo имеет большой размер. Извлекать массив маленьких структур из файла не накладно, а когда нам понадобится большая структура, её можно извлечь по уже известному адресу в файле.

Fread — Бинарно-безопасное чтение файла

Всем привет!
Продолжаем изучать основы PHP с нуля! В этом уроке я расскажу вам про дополнительные возможности по работе с файлами, а именно:
-проверить наличие файла;
-узнать размер файла;
-создать временный файл;

Проверить наличие файла на php.

Были у меня случаи, когда нужно было проверить кодом наличие файла.
Если и у вас есть необходимость проверить кодом наличие файла, воспользуйтесь функцией — file_exists().

На практике это будет выглядеть вот так:

Если файл « file.txt » существует, то на экране вы увидите сообщение « Файл существует »; если файла такого нет, тогда на экране появится противоположный текст « Файл не существует ».

Вы обратили внимание, что я использовал функцию file_exists() в конструкции if else?

Внимание: Может случиться так, что папка может иметь имя « file.txt » и скрипт воспримет, что файл существует, хотя это не файл, а папка. Поэтому лучше использовать функцию is_file() .

Узнать размер файла на php

Если нужно узнать размер файла, воспользуйтесь функцией filesize() :

На практике это будет выглядеть вот так:

В результате вы увидите на экране:

Размер файла file.txt — 96 байт


Создание временного файла, сделать в нем запись и вывести содержимое на экран.

Чтобы записать текст во временный файл, воспользуйтесь функцией tmpfile()

tmpfile() – Создаёт временный файл с уникальным именем, открывая его в режиме чтения и записи (w+).
fseek () – указатель положения в файле. Пример:

fread() – Бинарно-безопасное чтение файла. Пример:

1024 – Чтение останавливается при достижении 1024 байтов

В результате вы увидите на экране текст, записанный во временном файле:

Эта строка записывается во временный файл.

Вывести количество строк на экран

Если вам нужно определить количество строк в файле, воспользуйтесь функцией count() .

В результате вы увидите на экране вот такой текст:

Результат «1», так как в файле « file.txt » только одна строка.

Как вывести часть строки PHP?
Если вам нужно вывести только часть строки, воспользуйтесь функцией substr() :

Так как отсчет в тексте начался с « 4 » и длину текста я указал « 1 », то результат на экране будет:

Можно добавить в конце какие-то символы показывающие, что должно быть продолжение в тексте, например, троеточие (…) .

Как вывести определенную строку из файла на PHP?
Если вам нужно вывести определенную строку из файла на PHP, тогда воспользуйтесь вот такой конструкцией:

Если в файле « file.txt » содержится две строки, тогда на экране вы увидите вторую строку.

file() — Читает содержимое файла и помещает его в массив
$fopen[1] – если у вас возник вопрос, что это такое, тогда вам следует вернуться и повторить урок массивы php.

Полный пример с записью текста в файл:

В результате на экране вы увидите:

Как удалить определенную строку из файла на PHP?
Если вам нужно удалить любую строку в файле, воспользуйтесь вот такой конструкцией:

Давайте в примере создадим файл, сделаем там запись в три строки и потом удалим любую из строк и все это сделаем через код php:

В чем разница этих двух вариантов? Предлагаю поискать самостоятельно для лучшего изучения кода.
Итак, результат на экране будет таким:

1 строка. Я рад вас видеть на блоге stepkinblog.ru
3 строка. Я рад

Еще раз повторюсь, что отсчет начинается с нуля, то есть, если бы вы захотели удалить первую строку, то нужно было прописать в массиве « 0 »:

Для первого кода так:

Я думаю, всем ясно. Двигаемся дальше.

Как очистить файл на PHP?
Если вам нужно очистить всё содержимое файла, тогда воспользуйтесь функцией ftruncate().

— дескриптор_файла — это имя файл, который нужно очистить (файл должен быть открыт для записи « fopen() »);

— размер_файла – это размер файла, до которого он будет обрезан. Значение «0», файл будет полностью стертый.

В результате, если файл « stepkinblog-ru.txt » был чем-то заполнен, то после запуска скрипта файл будет пустым. Не верите? Проверьте. Откройте файл « stepkinblog-ru.txt ».

Как узнать дату последнего изменения на PHP?
Чтобы узнать дату последнего изменения файла, используйте функцию filemtime() .

fread fread

Считывает данные из потока. Reads data from a stream.

Синтаксис Syntax

Параметры Parameters

buffer buffer
Место хранения данных. Storage location for data.

size size
Размер элемента в байтах. Item size in bytes.

count count
Максимальное число читаемых элементов. Maximum number of items to be read.

вышестоящий stream
Указатель на структуру FILE. Pointer to FILE structure.

Возвращаемое значение Return Value

fread возвращает число фактически считанных полных элементов, которое может быть меньше, Если возникает ошибка или если конец файла обнаружен до достижения количестваобращений. fread returns the number of full items actually read, which may be less than count if an error occurs or if the end of the file is encountered before reaching count. Используйте функцию feof или ferror , чтобы отличать ошибку чтения от условия конца файла. Use the feof or ferror function to distinguish a read error from an end-of-file condition. Если параметр size или Count имеет значение 0, fread возвращает 0, а содержимое буфера не изменяется. If size or count is 0, fread returns 0 and the buffer contents are unchanged. Если Stream или buffer является пустым указателем, fread вызывает обработчик недопустимого параметра, как описано в разделе Проверка параметров. If stream or buffer is a null pointer, fread invokes the invalid parameter handler, as described in Parameter Validation. Если выполнение может быть продолжено, эта функция устанавливает еинвал и возвращает 0. If execution is allowed to continue, this function sets errno to EINVAL and returns 0.

Дополнительные сведения об этих кодах ошибок см. в разделе _досеррно, код ошибки,_ _sys еррлист _и_sys Нерр . See _doserrno, errno, _sys_errlist, and _sys_nerr for more information on these error codes.

Примечания Remarks

Функция fread считывает до подсчета размера байтов из входного потока и сохраняет их в буфер. The fread function reads up to count items of size bytes from the input stream and stores them in buffer. Указатель файла, связанный с потоком (при его наличии), увеличивается на число фактически считанных байтов. The file pointer associated with stream (if there is one) is increased by the number of bytes actually read. Если данный поток открыт в текстовом режиме, то символы новой строки в стиле Windows преобразуются в символы новой строки в стиле UNIX. If the given stream is opened in text mode, Windows-style newlines are converted into Unix-style newlines. То есть пары символов возврата каретки и перевода строки (CRLF) заменяются символами перевода строки (LF). That is, carriage return-line feed (CRLF) pairs are replaced by single line feed (LF) characters. Замена не влияет на указатель файла или возвращаемое значение. The replacement has no effect on the file pointer or the return value. В случае ошибки позиция указателя файла будет неопределенной. The file-pointer position is indeterminate if an error occurs. Значение частично считанного элемента не может быть определено. The value of a partially read item cannot be determined.

При использовании в потоке текстового режима, если объем запрошенных данных (то есть число размеров * ) больше или равен размеру внутреннего буфера файла * (по умолчанию это 4096 байта, можно настроить с помощью setvbuf), потоковые данные копируются непосредственно в предоставленный пользователем буфер, а в этом буфере выполняется преобразование новой строки. When used on a text mode stream, if the amount of data requested (that is, size * count) is greater than or equal to the internal FILE * buffer size (by default this is 4096 bytes, configurable by using setvbuf), stream data is copied directly into the user-provided buffer, and newline conversion is done in that buffer. Поскольку преобразованные данные могут быть короче, чем данные потока, скопированные в буфер, данные, превышающие Размер буфера[RETURN_VALUE * ] (где RETURN_VALUE является возвращаемым значением из fread), могут содержат непреобразованные данные из файла. Since the converted data may be shorter than the stream data copied into the buffer, data past buffer[return_value * size] (where return_value is the return value from fread) may contain unconverted data from the file. По этой причине мы советуем использовать символьные данные, заканчивающиеся нулем, в буфере[RETURN_VALUE * size], если целью буфера является работа в качестве строки в стиле C. For this reason, we recommend you null-terminate character data at buffer[return_value * size] if the intent of the buffer is to act as a C-style string. Дополнительные сведения о влиянии текстового и двоичного режимов см. в разделе fopen . See fopen for details on the effects of text mode and binary mode.

Эта функция блокирует работу других потоков. This function locks out other threads. Если требуется версия без блокировки, используйте _fread_nolock. If you need a non-locking version, use _fread_nolock.

Требования Requirements

Внимание
Функция Function Обязательный заголовок Required header
fread fread

Дополнительные сведения о совместимости см. в разделе Совместимость. For additional compatibility information, see Compatibility.

Запись в файл. fwrite() fread();

Доброго времени, уважаемые.

Пример взял с сайта для изучения C++. При записи в файл в нем самом отображается ерунда, но не то, что надо. С чего бы это?

2 ответа 2

fread/fwrite функции читают/пишут данные в бинарном формате. Если хочется человеко-читаемый (текстовый) формат, то можно использовать fscanf/fprintf вместо fread/fwrite соответственно.


Приведённый в вопросе код должен работать как есть.

Что конкретно fwrite запишет на диск, может зависеть от платформы (размер типа (LLP64, LP64 модели), порядок байтов, и даже побитовое представление типов (дополнительный код, обратный код), выравнивание типов).

Например, если файл скопировать на другую платформу, то не обязательно что fread сможет его прочитать корректно.

На моей машине test файл содержит:

Первая колонка, нумерует байты, в каждой строке по 16 байт, представленных командой xxd ввиде шестнадцатеричных чисел (каждые две цифры соответствуют одному байту). Самая правая колонка показывает печатаемые байты (точка используется для непечатаемых в ascii символов).

Вот байты соответствующие каждому значению:

Можно сразу сказать, что int является 32-битным типом (4 байта, предполагая 1 байт = 8 бит), а long 64-битным типом (что верно для lp64 модели) с порядком байтов от младшего с старшему (little-endian) на моей машине.

Если записать байты для i и l в порядке от старшего к младшему (big-endian) как обычно числа записаны на бумаге пишут:

  • int i 00000065 в шестнадцатеричной системе соответствует 101 в десятичной системе(6516 = 10110), что является корректным значением для i
  • long l 000000000001e08f в шестнадцатеричной системе соответствует 123023 в десятичной системе (1e08f16 = 12302310), что также верно.

Число d записано как число двойной точности в IEEE 754 формате —
d = ±знак · (1 + мантисса / 2 52 ) · 2 порядок − 1023 :

(cнова переписал байты от старшего к младшему) Или в двоичной системе — все 64 бита числа d :

Самый левый бит это знак, в данном случае он 0 , то есть d является положительным, затем 11 бит порядок = 100000000102 = 102610, оставшиеся 52 бита мантисса:

1000011101011100001010001111010111000010100011110112
= 238127830297215010
= 875c28f5c28f616

d = (1 + 2381278302972150 / 2 52 ) · 2 1026 − 1023
= 3442438965171323 / 281474976710656
= 12.23

Fread и бинарное чтение файла

Потому что printf выводит строку вплоть до первого терминирующего символа (‘\0’). Или считывайте отдельно каждое поле, не забывая добавлять в конец каждого массива (строки) этот ноль, либо выводите не printf-ом, а с помощью цикла for строго необходимое количество символов.

Потому что printf выводит строку вплоть до первого терминирующего символа (‘\0’). Или считывайте отдельно каждое поле, не забывая добавлять в конец каждого массива (строки) этот ноль, либо выводите не printf-ом, а с помощью цикла for строго необходимое количество символов.

смысл было в a[3] заносить \0, если потом его не копировать ) да и копировать его некуда, собственно. Так что по-сути ничего не изменилось, о чём и говорит результат.

видимо, он рассматиривает id как null-terminated строку. А так как никакого null у вас в конце строки нет, то он и шпарит дальше, пока не найдёт \0.

почему strlen(fr. >вроде уже 3 раза сказали. Строки заканчиваются \0. Так принято. \0 в конце id у вас отсутствует. Бывает. Вот strlen() и сканирует всю память, которая встретится после id (а там встречается 3 байта от size и дальше мусор). Вот этот мусор вы и наблюдаете на экране. Случано на 11-том байте оказался \0. Повезло. А могло ещё пару килобайт мусора быть. И это всё считалось бы строкой.Вы уже решите одно из двух:1) описываем структуру так, как байты лежат в файле. Это позволяет читать из файла всю структуру напрямую, но не позволяет рассматривать поля структуры как строки.ЛИБО 2) описываем поля структры как строки. Это не позволяет прочесть из файла всю структуру за раз, по позволяет работать с полями как со строками. Вы же упорно пытаетесь смешать эти два подхода.

Fread — Бинарно-безопасное чтение файла

Контакты: о проблемах с регистрацией, почтой и по другим вопросам пишите сюда — alarforum@yandex.ru, проверяйте папку спам! Обязательно пройдите активизацию e-mail.

Форум программистов > C++ > C++ Builder
fread и бинарное чтение файла
Регистрация
Поиск по форуму
Расширенный поиск
К странице.
Страница 1 из 2 1 2 Следующая >

Всем добрый день.
Прошу помощи у знатоков в решении проблемы))

При считывании файла в бинарном режиме(содержимое файла жирным):
50 49 43 40 50 23 00 4A 50 47 00 00 FF D8 FF E0 00 10

fread считывает как то непонятно(или я не правильно делаю)
Вместо:

PIC
@P#

почему в TFrame.id «записалось» содержимое след. 3 байт?
витчер среды ХЕ2 отображает нормально

но почему при выводе и использовании я зачем то получаю и ещё следующие 3 байта?

02.06.2012, 11:52 #1
02.06.2012, 12:22 #2
02.06.2012, 13:27 #3
02.06.2012, 14:03 #4
02.06.2012, 14:26 #5
02.06.2012, 14:30 #6
02.06.2012, 14:34 #7

вывод более ужасен
PIC@P#↑@x*↑
@P#↑@x*↑

НО почему strlen(fr. > а sizeof(fr. >

02.06.2012, 14:55 #8
02.06.2012, 16:40 #9
почему strlen(fr. >

вроде уже 3 раза сказали. Строки заканчиваются \0. Так принято. \0 в конце id у вас отсутствует. Бывает. Вот strlen() и сканирует всю память, которая встретится после id (а там встречается 3 байта от size и дальше мусор). Вот этот мусор вы и наблюдаете на экране. Случано на 11-том байте оказался \0. Повезло. А могло ещё пару килобайт мусора быть. И это всё считалось бы строкой.

Вы уже решите одно из двух:

1) описываем структуру так, как байты лежат в файле. Это позволяет читать из файла всю структуру напрямую, но не позволяет рассматривать поля структуры как строки.

2) описываем поля структры как строки. Это не позволяет прочесть из файла всю структуру за раз, по позволяет работать с полями как со строками.

Fread — Бинарно-безопасное чтение файла

size_t fread(void * ptr , size_t size , size_t nmemb , FILE * stream );

size_t fwrite(const void * ptr , size_t size , size_t nmemb , FILE * stream );

ОПИСАНИЕ

Функция fwrite записывает элементы данных nmemb (с размером каждого size байтов) в поток, на который указывает stream , при получении элементов с той позиции, на которую указывает ptr .

ВОЗВРАЩАЕМЫЕ ЗНАЧЕНИЯ

fread не определяет, действительно ли произошла ошибка или достигнут конец файла; для точного определения необходимо вызывать функции feof (3) и ferror (3).

Илон Маск рекомендует:  Что такое код vpopmail_passwd
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL