C Language
Файлы и потоки ввода-вывода
Модификации режима в fopen() и freopen() могут быть одним из следующих значений:
- "r" : открыть файл в режиме только для чтения, при этом курсор установлен в начало файла.
- "r+" : открыть файл в режиме чтения-записи, при этом курсор установлен в начало файла.
- "w" : открыть или создать файл в режиме только для записи, при этом его содержимое обрезается до 0 байтов. Курсор установлен в начало файла.
- "w+" : открыть или создать файл в режиме чтения-записи, при этом его содержимое обрезается до 0 байтов. Курсор установлен в начало файла.
- "a" : открыть или создать файл в режиме только записи, при этом курсор установлен в конец файла.
- "a+" : открыть или создать файл в режиме чтения-записи, при этом указатель чтения установлен в начало файла. Выход, однако, всегда будет добавлен в конец файла.
Каждый из этих файловых режимов может иметь b добавленный после начальной буквы (например, "rb" или "a+b" или "ab+" ). b означает, что файл следует рассматривать как двоичный файл вместо текстового файла в тех системах, где есть разница. Это не влияет на Unix-подобные системы; это важно для систем Windows. (Кроме того, Windows fopen позволяет явному t вместо b указывать «текстовый файл» и множество других параметров для конкретной платформы.)
- "wx" : создать текстовый файл в режиме только для записи. Файл может не существовать .
- "wbx" : создать двоичный файл в режиме только для записи. Файл может не существовать .
x , если присутствует, должен быть последним символом в строке режима.
Открыть и записать в файл
Эта программа открывает файл с именем, указанным в аргументе main, по output.txt для output.txt если аргумент не указан. Если файл с тем же именем уже существует, его содержимое отбрасывается, и файл рассматривается как новый пустой файл. Если файлы еще не существуют, создается вызов fopen() .
Если по какой-либо причине вызов fopen() завершился с ошибкой, он возвращает значение NULL и устанавливает значение глобальной переменной errno . Это означает, что программа может проверить возвращаемое значение после вызова fopen() и использовать perror() если fopen() терпит неудачу.
Если вызов fopen() завершается успешно, он возвращает действительный указатель FILE . Этот указатель затем может использоваться для ссылки на этот файл до тех пор, пока на нем не будет fclose() .
Функция fputs() записывает данный текст в открытый файл, заменяя любое предыдущее содержимое файла. Аналогично функции fopen() функция fputs() также устанавливает значение errno если она терпит неудачу, хотя в этом случае функция возвращает EOF для указания отказа (иначе он возвращает неотрицательное значение).
Функция fclose() сбрасывает любые буферы, закрывает файл и освобождает память, на которую указывает FILE * . Возвращаемое значение указывает на завершение так же, как и fputs() (хотя при успешном завершении возвращает «0»), снова также устанавливая значение errno в случае сбоя.
fprintf
Вы можете использовать fprintf в файле так же, как на консоли с printf . Например, чтобы отслеживать выигрыши игр, потери и связи, которые вы могли бы написать
Замечание: некоторые системы (печально, Windows) не используют то, что большинство программистов назвали бы «нормальными» окончаниями строк. Хотя UNIX-подобные системы используют \ n для завершения строк, Windows использует пару символов: \ r (возврат каретки) и \ n (строка). Эта последовательность обычно называется CRLF. Однако при использовании C вам не нужно беспокоиться об этих деталях, зависящих от платформы. AC-компилятор необходим для преобразования каждого экземпляра \ n в правильную конечную строку платформы. Поэтому компилятор Windows будет конвертировать \ n в \ r \ n, но компилятор UNIX сохранит его как есть.
Выполнить процесс
Эта программа запускает процесс ( netstat ) через popen() и считывает весь стандартный вывод процесса и выводит его на стандартный вывод.
Примечание: popen() не существует в стандартной библиотеке C , но это скорее часть POSIX C )
Получить строки из файла с помощью getline ()
Библиотека POSIX C определяет функцию getline() . Эта функция выделяет буфер для хранения содержимого строки и возвращает новую строку, количество символов в строке и размер буфера.
Пример программы, которая получает каждую строку из example.txt :
Входной файл example.txt
Выход
В этом примере getline() изначально вызывается без выделенного буфера. Во время этого первого вызова getline() выделяет буфер, считывает первую строку и помещает содержимое строки в новый буфер. При последующих вызовах getline() обновляет один и тот же буфер и перераспределяет буфер только тогда, когда он больше не достаточно большой, чтобы соответствовать всей строке. Затем временный буфер освобождается, когда мы закончили с файлом.
Другой вариант — getdelim() . Это то же самое, что и getline() за исключением указания символа окончания строки. Это необходимо, только если последний символ строки для вашего типа файла не является \ n. getline() работает даже с текстовыми файлами Windows, потому что с завершением многобайтовой строки ( "\r\n") '\ n'` по-прежнему остается последним символом в строке.
Пример реализации getline()
Открыть и записать в двоичный файл
Эта программа создает и записывает текст в двоичной форме через функцию fwrite в файл output.bin .
Если файл с тем же именем уже существует, его содержимое отбрасывается, и файл рассматривается как новый пустой файл.
Бинарный поток представляет собой упорядоченную последовательность символов, которая может прозрачно записывать внутренние данные. В этом режиме байты записываются между программой и файлом без какой-либо интерпретации.
Чтобы записывать целые числа переносимым образом, необходимо знать, ожидает ли формат файла их в формате большой или малой длины, а также размер (обычно 16, 32 или 64 бита). Бит-сдвиг и маскирование могут затем использоваться для записи байтов в правильном порядке. Целые числа в C не гарантируют наличие двух дополняющих представлений (хотя почти все реализации выполняются). К счастью, преобразование в беззнаковый гарантированно использовать двойки комплемента. Поэтому код для записи знакового целого в двоичный файл немного удивителен.
Другие функции следуют одному и тому же шаблону с незначительными изменениями для размера и порядка байтов.
fscanf ()
Предположим, у нас есть текстовый файл, и мы хотим прочитать все слова в этом файле, чтобы выполнить некоторые требования.
file.txt :
Это основная функция:
Чтение строк из файла
Заголовок stdio.h определяет функцию fgets() . Эта функция считывает строку из потока и сохраняет ее в указанной строке. Функция прекращает чтение текста из потока, когда считывается n — 1 символ, читается символ новой строки ( '\n' ) или заканчивается конец файла (EOF).
Вызов программы с аргументом, который представляет собой путь к файлу, содержащему следующий текст:
Результатом будет следующий вывод:
Этот очень простой пример позволяет фиксированную максимальную длину строки, так что более длинные строки будут эффективно считаться двумя строками. Функция fgets() требует, чтобы вызывающий код предоставлял память, которая будет использоваться в качестве адресата для прочитанной строки.
POSIX делает доступной функцию getline() которая вместо этого внутренне выделяет память, чтобы увеличить буфер, если необходимо, для линии любой длины (при условии, что имеется достаточная память).
Как записать в конец файла c
Файловая система FAT32 имеет следующую структуру.
Нумерация кластеров, используемых для записи файлов, ведется с 2. Как правило, кластер №2 используется корневым каталогом, а начиная с кластера №3 хранится массив данных. Сектора, используемые для хранения информации, представленной выше корневого каталога, в кластеры не объединяются.
Минимальный размер файла, занимаемый на диске, соответствует 1 кластеру.
- EB 58 90 – безусловный переход и сигнатура;
- 4D 53 44 4F 53 35 2E 30 MSDOS5.0;
- 00 02 – количество байт в секторе (обычно 512);
- 1 байт – количество секторов в кластере;
- 2 байта – количество резервных секторов.
- 0x10 (1 байт) – количество таблиц FAT (обычно 2);
- 0x20 (4 байта) – количество секторов на диске;
- 0x2С (4 байта) – номер кластера корневого каталога;
- 0x47 (11 байт) – метка тома;
- 0x1FE (2 байта) – сигнатура загрузочного сектора ( 55 AA ).
- 0x00 (4 байта) – сигнатура ( 52 52 61 41 );
- 0x1E4 (4 байта) – сигнатура ( 72 72 41 61 );
- 0x1E8 (4 байта) – количество свободных кластеров, -1 если не известно;
- 0x1EС (4 байта) – номер последнего записанного кластера;
- 0x1FE (2 байта) – сигнатура ( 55 AA ).
- 00 00 00 00 – кластер свободен;
- FF FF FF 0F – конец текущего файла.
- 8 байт – имя файла;
- 3 байта – расширение файла;
- 8 байт – имя файла;
- 3 байта – расширение файла;
- 1 байт – атрибут файла:

- 1 байт – зарезервирован;
- 1 байт – время создания (миллисекунды) (число от 0 до 199);
- 2 байта – время создания (с точностью до 2с):

- 2 байта – дата создания:

- 2 байта – дата последнего доступа;
- 2 байта – старшие 2 байта начального кластера;
- 2 байта – время последней модификации;
- 2 байта – дата последней модификации;
- 2 байта – младшие 2 байта начального кластера;
- 4 байта – размер файла (в байтах).
Append lines to a file using a StreamWriter
I want to append lines to my file. I am using a StreamWriter:
The output of my file should be several strings below each other, but I have only one row, which is overwritten every time I run this code.
Is there some way to let the StreamWriter append to an existing file?
11 Answers 11
Use this instead:
With this overload of the StreamWriter constructor you choose if you append the file, or overwrite it.
C# 4 and above offers the following syntax, which some find more readable:
![]()
I assume you are executing all of the above code each time you write something to the file. Each time the stream for the file is opened, its seek pointer is positioned at the beginning so all writes end up overwriting what was there before.
Потоки (Streams) и ввод-вывод (IO) в C#
Ввод-вывод строится на основе потоков. Большинство классов для работы с потоками и вводом-выводом находится в пространстве имен System.IO .
Потоковая архитектура
В основе потоковой архитектуры .NET лежат три понятия:
- опорное хранилище (backing store)
- декоратор (decorator)
- адаптер (adapter)
Опорное хранилище — это конечная точка ввода-вывода: файл, сетевое подключение и т.д. Оно может представлять собой либо источник, из которого последовательно считываются байты, либо приемник, куда байты последовательно записываются, либо и то и другое вместе.
Чтобы использовать опорное хранилище его нужно открыть. Этой цели и служат потоки, которые в .NET представлены классом System.IO.Stream , содержащий методы для чтения, записи и позиционирования потоков.
Потоки не загружают опорное хранилище в память целиком, а читают его последовательно по байтам либо блокам управляемого размера. Поэтому поток может потреблять мало памяти независимо от размера его опорного хранилища.
Потоки делятся на две категории:
- потоки опорных хранилищ — потоки, жестко привязанные к конкретным типам опорных хранилищ, такие как FileStream или NetworkStream
- потоки-декораторы — наполняют другие потоки, трансформируя данные тем или иным способом, такие как DeflateStream или CryptoStream
Декораторы освобождают потоки опорных хранилищ от необходимости самостоятельно реализовывать такие вещи, как сжатие и шифрование. Декораторы можно подключать во время выполнения, а также соединять их в цепочки (т.е. использовать несколько декораторов в одном потоке).
Потоки работают с байтами. Это гибко и эффективно, но не всегда удобно, например, когда приложение имеет дело с текстом или XML. Преодолеть этот разрыв позволяютадаптеры, они помещают поток в оболочку класса со специальными методами для конкретного формата. В отличие от декораторов адаптеры сами не являются потоками, они обычно полностью скрывают байт-ориентированные методы.
Потоки
Абстрактный класс Stream является базовым для всех потоков. Он определяет методы и свойства для трех фундаментальных операций: чтение, запись и поиск, а также для выполнения служебных задач: закрытие, сброс, конфигурирование тайм-аутов:
Кроме того класс содержит асинхронные методы для чтения и записи: ReadAsync и WriteAsync :
Чтение и запись
Поток может поддерживать чтение, запись или то и другое. Если свойство CanWrite возвращает false — поток предназначен только для чтения, если CanRead возвращает false — поток предназначен только для записи.
Метод Read читает блок данных из потока и записывает их в массив. Он возвращает количество полученных байтов, которое может быть либо равно, либо меньше значения аргумента count . Если оно меньше count — это значит, что достигнут конец потока или поток выдает данные порциями меньшего размера (в связи с этим однозначно судить о том, что достигнут конец потока можно только если метод возвращает 0):
Метод ReadByte читает один байт из потока, в случае достижения конца потока возвращает -1.
Методы Write и WriteByte отправляют данные в поток, в случае неудачи генерируют исключение.
Аргумент offset методов Read и Write ссылается на индекс в массиве buffer , с которого начинается чтение или запись, а не на позицию в потоке.
Позиционирование (Seeking)
Если свойство CanSeek возвращает true , то поток поддерживает возможность позиционирования. Для такого потока можно запрашивать свойство Length и модифицировать его с помощью метода SetLength . Также можно в любой момент изменять свойство Position , отражающее позицию относительно начала потока, в которой производится чтение или запись. Метод Seek позволяет перемещаться относительно текущей позиции или относительно конца потока.
Если поток не поддерживает возможность позиционирования, единственный способ определить длину потока — прочитать его до конца. К тому же, если требуется повторно прочитать предшествующую область, необходимо закрыть поток и начать все заново.
Закрытие и сброс
Потоки должны быть освобождены после использования, чтобы освободить лежащие в их основе ресурсы. Самый простой способ обеспечения этого — создание экземпляров потока внутри блока using .
Помимо этого потоки содержат методы Dispose и Close (функционально идентичны, закрывают поток). Многократное освобождение или закрытие потока не вызывает ошибки.
Закрытие потока с декоратором закрывает и декоратор и поток с опорным хранилищем. В случае цепочки декораторов закрытие самого внешнего декоратора закрывает всю цепочку.
Для улучшения производительности некоторые потоки буферизуют данные, поступающие в/из опорного хранилища. По этой причине данные записываемые в поток могут не сразу попадать в опорное хранилище, возможна задержка до заполнения буфера. Метод Flush обеспечивает принудительную запись любых буферизированных данных. При закрытие потока метод Flush вызывается автоматически.
Тайм-ауты
Если свойство CanTimeout возвращает true , поток поддерживает тайм-аут чтения и записи (тайм-ауты поддерживают сетевые потоки, а файловые и потоки в памяти — нет). Для таких потоков свойство ReadTimeout задает тайм-аут в миллисекундах на чтение, а свойство WriteTimeout — тайм-аут на запись. Ноль означает отсутствие тайм-аута. При наступлении тайм-аута методы Read и Write генерируют исключения.
Потоки с опорными хранилищами в .NET
Основными потоками с опорными хранилищами в .NET являются:
- System.IO.FileStream
- System.IO.MemoryStream
- System.IO.IsolatedStorageFileStream
- System.Net.Sockets.NetworkStream
- System.IO.Pipes.PipeStream
Декораторы в .NET
Декораторы помещают другой поток в оболочку, добавляя ему различный функционал. Основными декораторами в .NET являются:
- System.IO.BufferedStream
- System.IO.Compression.DeflateStream
- System.IO.Compression.GZipStream
- System.Security.Cryptography.CryptoStream
- System.Net.Security.AuthenticatedStream
Адаптеры потоков в .NET
Текстовые адаптеры (для типов string и char ):
- TextReader
- TextWriter
- StreamReader
- StreamWriter
- StringReader
- StringWriter
Двоичные адаптеры (для типов int , bool , string и float ):
- BinaryReader
- BinaryWriter
- XmlReader
- XmlWriter
FileStream
Создать экземпляр FileStream можно с помощью статических методов класса File :