17 что такое файловые потоки ввода вывода
Файл — это упорядоченная и именованная последовательность байтов, имеющая постоянное хранилище. При работе с файлами используются пути к каталогам, запоминающие устройства, а также имена файлов и каталогов. В отличие от файла, поток — это последовательность байтов, которую можно использовать для записи или чтения из вспомогательного запоминающего устройства, являющегося одним из устройств хранения информации (например, дисков или памяти). Есть несколько видов запоминающих устройств, отличных от дисков, и существует несколько видов потоков, помимо файловых потоков, например сетевые потоки, потоки памяти и потоки каналов.
Операции ввода-вывода в приложениях Microsoft Store
Следует отметить некоторые важные различия в использовании операций ввода-вывода в приложениях Microsoft Store для Windows 8.x:
Изолированное хранилище недоступно; вместо этого используйте данные приложения.
Используйте асинхронные методы, такие как ReadAsync и WriteAsync, чтобы предотвратить блокировку потока пользовательского интерфейса.
Дополнительные сведения об операциях ввода-вывода в приложении Microsoft Store для Windows 8.x: Краткое руководство. Чтение и запись файлов.
2 Файловые потоки
Файлы данных
Под файлами данных будем понимать хранилища информации в энергонезависимой памяти компьютера. Каждый файл имеет путевое имя в файловой системе, права на чтение/запись, размер.
Файлы данных используются для хранения информации в перерывах между сеансами работы пользователей.
Для работы с файлами данных в С++ используются специальные файловые потоки
Порядок работы с файлом
При работе с файлом придерживаются следующей последовательности:
- Открытие файла (создание потокового объекта).
- Проверка результата открытия.
- Чтение/запись данных.
- Закрытие файла.
Иногда после открытия требуется позиционирование, то есть перемещение к нужной позиции внутри открытого файла.
Открытие файла
Для работы с файлами мы подключаем заголовочный файл fstream
Заголовочный файл определяет несколько потоков для работы с файлами
- ifstream - для чтения данных из файла
- ofstream - для записи данных в файл
- fstream - для записи и чтения данных
В следующем примере файл 1.txt открывается для чтения, а 2.txt - для записи:
Открывать файлы можно другим способом.
Сначала создаются объекты файловых потоков, а затем вызывается метод open() файлового потока:
У данного способа есть два преимущества:
- Можно снова открыть тот же самый файл после закрытия не создавая новый потоковый объект.
- Один и тот же потоковый объект может применяться для открытия нескольких файлов (последовательно).
При открытии файла необходимо указать его путевое имя. Путевое имя может быть относительным и абсолютным.
Относительное имя
Короткое имя файла в текущем каталоге
Абсолютное (полное) имя
Путевое имя файла в операционной системе
Пример с использованием полного имени в ОС Windows:
Следует обратить внимание на то, что обратный слэш в строковых константах должен удваиваться.
Пример с использованием полного имени в ОС Unix:
У файловых объектов есть функция fail(), которая в случае ошибки открытия возвращает истинное значение.
При открытии на чтение, входной файл должен существовать.
При открытии на запись, файлу существовать необязательно, поскольку он все равно будет создан.
Закрытие файла
Для закрытия файла используется функция close().
При закрытии файла, в который производилась запись, все данные будут записаны на диск.
Чтение данных
Чтение данных из файла может осуществляться разными способами:
- посимвольно (побайтно);
- поэлементно (до пробела или перевода строки);
- построчно;
- поблочно.
Посимвольное чтение
В следующем примере файл читается посимвольно.
Построчное чтение
В следующем примере файл читается построчно.
Еще один пример функции, читающей файл построчно:
Поэлементное чтение
При поэлементном чтении мы используем операцию извлечения данных из потока, которая срабатывает до ближайшего разделителя (пробела или перевода строки).
Поблочное чтение
Поблочное чтение означает, что из файла читается блок данных определенного размера.
В следующем примере мы читаем из файла структуру BOOK:
После чтения, позиция внутри файла сдвигается на размер структуры BOOK.
Запись в файлы
Операциям чтения данных из файла соответствуют операции записи данных.
Операции get соответствует put, операции read - write.
В следующем примере показано использование операции помещения информации в поток:
В файл 2.txt помещается 10 строк с приветствием и его порядковым номером. При выводе в файл числовых значений они будут преобразованы в строки.
Запись и чтение
Файл можно открыть для записи и чтения:
С каждой операцией записи/чтения позиция внутри файла сдвигается на определенное число байт, равное размеру записанных или прочитанных данных. Для изменения текущей позиции надо использовать метод seekp().
Возможные варианты второго параметра seekp()
- pos::beg - начало файла
- pos::end - конец файла
- pos::cur - текущая позиция (любая)
Бинарный и текстовый режимы
Работа с файлом может происходить в бинарном или текстовом режиме. По-умолчанию, используется текстовый режим.
В текстовом режиме при вводе/выводе символа перевода строки автоматически удаляется/добавляется символ возврата каретки.
Стандартные потоки ввода и вывода в UNIX/Linux наряду с файлами являются одним из наиболее распространённых средств для обмена информацией процессов с внешним миром, а перенаправления >, >> и |, одной из самых популярных конструкций командного интерпретатора.
На этой странице рассматриваются как базовые вопросы использования потоков ввода/вывода, так и тонкости и хитрости, например, почему не работает echo text | read ver и многие другие.
Потоки
Абстрактный базовый класс Stream поддерживает чтение и запись байтов. Все классы, представляющие потоки, являются производными от класса Stream. Класс Stream и его производные классы обеспечивают общий способ просмотра источников данных и хранилищ объектов, а также изолируют программиста от специфических особенностей операционной системы и базовых устройств.
Потоки включают три основные операции:
Чтение — перенос информации из потока в структуру данных, такую как массив байтов.
Запись — перенос данных в поток из источника данных.
Поиск — определение и изменение текущей позиции внутри потока.
В зависимости от базового источника или хранилища данных поток может поддерживать лишь некоторые из этих возможностей. Например, класс PipeStream не поддерживает поиск. Свойства CanRead, CanWrite и CanSeek потока определяют операции, поддерживаемые потоком.
Ниже перечислены некоторые часто используемые классы потока:
FileStream — для чтения и записи в файл.
IsolatedStorageFileStream — для чтения и записи в файл в изолированном хранилище.
MemoryStream — для чтения и записи в память в качестве резервного хранилища.
BufferedStream — для повышения быстродействия операций чтения и записи.
NetworkStream — для чтения и записи на сетевые сокеты.
PipeStream — для чтения и записи в анонимные и именованные каналы.
CryptoStream — для связи потоков данных с криптографическими преобразованиями.
Пример асинхронной работы с потоками см. в разделе Асинхронный файловый ввод-вывод.
Файлы и каталоги
Типы в пространстве имен System.IO можно использовать для взаимодействия с файлами и каталогами. Например, можно получать и задавать свойства файлов и каталогов, а также извлекать коллекции файлов и каталогов на основе критерия поиска.
Ниже перечислены некоторые часто используемые классы для файлов и каталогов:
File предоставляет статические методы для создания, копирования, удаления, перемещения и открытия файлов, а также помогает создать объект FileStream.
FileInfo предоставляет методы экземпляра для создания, копирования, удаления, перемещения и открытия файлов, а также помогает создать объект FileStream.
Directory предоставляет статические методы для создания, перемещения и перечисления в каталогах и подкаталогах.
DirectoryInfo предоставляет методы экземпляра для создания, перемещения и перечисления в каталогах и подкаталогах.
Path предоставляет методы и свойства для обработки строк каталогов межплатформенным способом.
При вызове методов для работы с файловой системой следует всегда использовать надежные механизмы обработки исключений. Дополнительные сведения см. в разделе об обработке ошибок ввода-вывода.
Помимо использования этих классов, пользователи Visual Basic могут использовать методы и свойства, предоставляемые классом Microsoft.VisualBasic.FileIO.FileSystem для файлового ввода-вывода.
Произвольный доступ к файлу
Система ввода-вывода С++ позволяет осуществлять произвольный доступ с использованием методов seekg() и seekp() .
Смещение определяет область значений в пределах файла ( long int ).
Система ввода-вывода С++ обрабатывает два указателя, ассоциированные с каждым файлом:
- get pointer g - определяет, где именно в файле будет производиться следующая операция ввода;
- put pointer p - определяет, где именно в файле будет производиться следующая операция вывода.
Позиция смещения определяется как
Позиция | Значение |
ios::beg | Начало файла |
ios::cur | Текущее положение |
ios::end | Конец файла |
Всякий раз, когда осуществляются операции ввода или вывода, соответствующий указатель автоматически перемещается.
С помощью методов seekg() и seekp() можно получить доступ к файлу в произвольном месте.
Можно определить текущую позицию файлового указателя, используя следующие функции:
- streampos tellg() - позиция для ввода
- streampos tellp() - позиция для вывода
В результате выполнения первой части программы будет создан файл
Вторая часть программы выведет в консоль
Ещё один пример. Допустим, нам нужно заполнять таблицу
Причем каждая вновь введенная строка должна размещаться в таблице непосредственно под "шапкой".
Алгоритм решения задачи следующий:
- формируем очередную строку для вывода
- открываем файл для чтения, считываем из него данные и сохраняем их в массив строк
- закрываем файл
- открываем файл для записи
- выводим "шапку" таблицы
- выводим новую строку
- выводим все сохраненные строки обратно в файл, начиная со строки после шапки
fstream inOut;
inOut.open( "file.txt" , ios::in); // открываем файл для ввода
// Считываем из файла имеющиеся данные
int count = 0;
while (inOut.getline(line[count], 100)) count++;
inOut.close(); // закрываем файл
Результат выполнения:
Полученный файл данных:
Здравствуйте Елена. Скажите, а можно ли как то узнать наступивший конец файла. Например, если количество строк в файле неизвестно, а нужно организовать цикл по их считыванию и прервать его по окончанию файла.
ifstream test( "U:\\prog struct17\\list.txt" ); // полное имя файла
if (!test) cout return 0;
while (!test.eof())< //пока не конец.
. >
Елена, здравствуйте! Помогите, пожалуйста. Есть код, работающий, но вывод делает в консоль, а так как вывод очень большой, то все результаты там не помещаются, только малая последняя часть. Подскажите, пожалуйста, где и что изменить, чтоб вывод записывало в файл. Если можно очень подробно или прям конкретным примером, я со всем этим только только столкнулась, поэтому пока не особо соображаю(( Вот мой код
import static java.lang.System.out;
import java.util.Arrays;
class Combinations
private static final int M = 12;
private static final int N = 24;
private static int [] generateCombinations( int [] arr)
if (arr == null)
arr = new int [M];
for ( int i = 0; i < M; i++)
arr[i] = i + 1;
return arr;
>
for ( int i = M - 1; i >= 0; i--)
if (arr[i] < N - M + i + 1)
arr[i]++;
for ( int j = i; j < M - 1; j++)
arr[j + 1] = arr[j] + 1;
return arr;
>
return null;
>
public static void main(String args[])
int [] arr = null;
while ((arr = generateCombinations(arr)) != null)
out.println(Arrays.toString(arr));
>
>
Думаю, что "в правильную". Можно попробовать взять, например, среднее арифметическое для каждой точки из двух файлов. Но это нужно анализировать при отладке.
Елена, здравствуйте. Подскажите, пожалуйста, как можно сделать так, чтобы из первой строки файла считывался размер массива, а из второй - его элементы, количество которых равно значению из первой строки. Не нашла у вас на сайте ничего про построчный ввод из файла. Заранее спасибо.
Ввод из файла осуществляется аналогично консольному вводу. После считывания порции данных указатель позиции файла автоматически перемещается на ее конец.
Да, но у вас в статьях нет ничего про, к примеру, getline. По вашим статьям я изучаю практически все, очень понятно и доходчиво написано, но этот блок то ли я не могу найти, то ли его нет. Подскажите, у вас на сайте есть статья, где более подробно описывается файловый ввод и вывод?
Здравствуйте, попыталась сделать вывод данных в файл, но почему то только создался документ, а данных там нет. Что не так?
ofstream fout( "file.txt" , ios::out);
fout.open( "file.txt" , ios::out);
for ( int i = 0; i < SIZE; i++)
for ( int j = 0; j < SIZE; j++)
printf( "%5d " , a[i][j]);
printf( "\n" );
Можно ли как-то скопировать половину строки ? Выше вы копировали от середины и до конца, но мне нужно наоборот- от начала до середины ( или 10-го символа)
Не совсем правильно сформулировала , от определённого индекса до определённого индекса. То есть, у нас есть строка(char sr[50]="blablablabla";) Я хочу скопировать с третього индекса по 10.
int main( int argc, char * argv[]) system( "chcp 1251" );
system( "cls" );
char line[LINES][150];
char str[30];
char s[] = "| | | | " ;
cout cin.getline(str, 30);
for ( int i = 0; str[i] != '\0'; i++)
s[i + 0] = str[i];
cout cin.getline(str, 30);
for ( int i = 0; str[i] != '\0'; i++)
s[i + 33] = str[i];
cout cin.getline(str, 30);
for ( int i = 0; str[i] != '\0'; i++)
s[i + 61] = str[i];
cout cin.getline(str, 30);
for ( int i = 0; str[i] != '\0'; i++)
s[i + 97] = str[i];
Почему файл объявлен как поток вывода, а открывается для ввода? Чему равен count? Где тут люди? Почему при вводе нет цикла?
Здравствуйте, подскажите как считать данные из файла, сохранённых в следующем виде: Check Type | Check name | Cost check | 12 |Full |50000 | 38 |Half |25000 | 156 |Special |79000 | и записать данные в структуру. Например: Поле "Struct->CheckType" имеет значение "12" Поле "Struct->CheckName" имеет значение "Full" Поле "Struct->CostCheck" имеет значение "50000"
Считывать по строкам, далее строку разделять по символу | и присваивать значения полям структуры. Если поля структуры целочисленные, то предусмотреть ещё перевод из строки в число.
Здравствуйте. Возникла проблема, когда пытался переделать ваш код под себя. Выдается очень странный баг, хотя программа компилируется. Я добавил возможность использования программы повторно, без перезапуска консоли, через цикл while. И немного изменил шапку и ее ввод. В общем вот код. Если получится найти причину, буду очень благодарен.
fstream abonent;
abonent.open( "file.txt" , ios::in);
int count = 0;
while (abonent.getline(line[count], 100)) count++;
abonent.close();
Пока вижу 2 бага, не знаю, какой Вы имеете в виду. 1. Когда вводим данные второго и последующих лиц, программа "глотает" Имя. 2. Если, допустим, фамилия второго человека окажется короче, чем у первого, то она будет дополнена "остатком" предыдущей фамилии.
Считать всю строку. Найти ее длину с помощью strlen() и сместить курсор на "минус" половину этого значения от текущей позиции.
Спасибо за статью. Познавательно. Пробую использовать данный вывод в файл, но возникла проблема: Файл создается и очищается (проверено) но запись в файл не происходит, и после выполнения данного кода
std::string textoutbuf = "yjjfhjshdsjhf dkcfjdhj jfcjh 111111" ;
textoutbuf.push_back('\n');
//m_sock.fileLog m_sock.fileLog INT qqq = GetLastError();
m_sock.fileLog.flush(); //очистить поток
m_sock.fileLog.close();
файл всегда нулевой длины. Что уже не пробовал, читал форумы но ответа пока не нашел. Может Вы подскажете в чем может быть проблема? Спасибо.
Возможно, я чего-то не учитываю, поскольку приведен только фрагмент кода. Но такая реализация позволит получить файл с данными:
А как записать данные в файл с названием, определяемым самим пользователем? Насколько я понял, в качестве названия файла можно использовать только константу (?)
извините, я наверно вас уже заколебал, с этой 4 строчкой. Но мне надо прочитать строчку из файла и вывести ее в консоль. Т.е. В файле есть 4 строка мне ее надо прочитать и вывести на экран. inOut.open( "file.txt" ,ios::out); for ( int i=0; i <4; i++) cout<
А как происходит перебор строк? Я как понимаю, мы читаем строку в массив line[1]; Потом читаем еще раз строку, но в массив line[2]; и т.д. до line[100]. А где мы говорим, что мы не читаем одну и туже строчку то? Как встать то на строчку 5? И прочитать что в строке 5 У нас Петров Петр.
Почему если в файле "file.txt" есть информация, то данный код не просто читает он удаляет все из файла?
При считывании строки указатель позиции в файле автоматически смещается на её длину. Поэтому если мы считаем 4 строки, то окажемся на начале 5-ой. Считав её, мы получим нужную нам информацию.
Если данные из файла считываются, то они не удаляются. Удаление данных происходит только при открытии файла в режиме записи (строка 32 последнего примера в статье).
Спасибо большое за ответы. Но а как мне получить строку под номером 4? Допустим я не знаю что в файле, и я хочу прочитать только 4 строчку. line[4] выводит все четвертые буквы всех строк, но не всю строку целиком. Может как то можно получить массив строк и массив символов за раз? Например my_line_txt[4][5] - четвертая строка 5 символ.
line[4] - это и есть 4-ая строка. Первый индекс в массиве line[][] - это номер строки, второй - номер символа в строке.
Подскажите пожалуйста (нигде найти не могу) Как выводить в файл строки сверху. было То, как зверь, она завоет, То заплачет, как дитя, Надо вставить сверху строчки, что бы получилось так: Буря мглою небо кроет, Вихри снежные крутя; То, как зверь, она завоет, То заплачет, как дитя, Только не говорите что для этого отдельный файл создавать надо. )
Если использовать флаг ios::beg Да, он ставит курсор в начало файла. Но он удалит весь текст который там был. И вставить строчку не получиться. Вместо вставки происходит замена.
Я, конечно, не буду говорить, что нужно создавать отдельный файл :) Но придётся считать всю информацию из файла и где-то её сохранить. Потом открыть файл для записи. Записать недостающие строки сверху, а потом снова выгрузить сохраненное содержимое файла.
А если надо заполнить такую таблицу что бы последние введенные данные были наверху. То есть, есть шапка которую нельзя трогать. файл 1 "с шапкой" файл 2 "с новой строкой" файл 3 = файл 1+файл2; // итоговый наш файл файл 2 = получили новую строку файл 4 = скопировать все с 4 строчки и ниже из файла №3 файл 3 = встаем на четвертую строчку и добавляем файл №2 с нашей строкой файл 3 = копируем все из файла 4. Только так можно это реализовать? Как можно установить курсор на 4 строчку? ----------------------------------------------------------------------------------- | Фамилия | Имя | Отчество | дата рождения | хобби | ----------------------------------------------------------------------------------- |_________|_____|__________|_______________|________| |_________|_____|__________|_______________|________| |_________|_____|__________|_______________|________| |_________|_____|__________|_______________|________|
Как можно установить курсор на 4 строчку? И как можно скопировать все что ниже 4 строчки. Или удалить все что выше 4 строчки.
Чтение данных из потока называется извлечением, а запись в поток- помещением.
Иерархия потоков
Потоки ввода/вывода
В языке С++ с каждым устройством ассоциируется поток ввода/вывода:
- cin - стандартный поток ввода (клавиатура)
- cout - стандартный поток вывода (терминал)
- cerr - стандартный поток ошибок.
При работе с потоками происходит автоматический перевод из типа данных в строку для вывода на экран и из строки в числовой тип при вводе.
Для работы со стандартными потоками подключается заголовочный файл iostream
Потоки ввода вывода
Данные разных типов можно смешивать:
Ввод/вывод строк
При вводе строк извлечение происходит до ближайшего пробела (или другого стандартного разделителя)
Для ввода строк целиком используются методы потоков get и getline.
В следующем примере демонстрируется ввод строк целиком
Ввод вывод строк
Для обеспечения безопасного ввода может применяться манипулятор setw:
Циклический ввод-вывод
Данный цикл позволяет ввести строку, а потом очищает ее от разделителей при выводе.
Циклическии ввод-вывод
Здесь осуществляется посимвольный ввод/вывод вместе с разделителями
Форматирование
С помощью механизма флагов можно управлять параметрами вывода данных на консоль.
Устанавливается значение флага через метод setf, а снимается с помощью unsetf.
Вывод логических величин в текстовом виде:
Основные флаги форматирования:
- left - левое выравнивание
- right - правое выравнивание
- boolalpha - вывод логических значений в текстовом виде
- dec - основание системы счисления 10
- oct - основание системы счисления 8
- hex - основание системы счисления 16
- showbase - выводить индикатор системы счисления
- showpos - показывать + для положительных чисел
- scientific - экспонециальная форма вещественного числа
- fixed - фиксированная форма вещественного числа
Помимо флагов, изменяющих состояние потока можно использовать манипуляторы.
Идея манипуляторов состоит в том, что их можно помещать в поток вместе с данными.
Многие манипуляторы повторяют названиями флаги.
Для работы с манипуляторами нужно подключить заголовочный файл iomanip.
- setw() - установить ширину поля
- setprecision() - количество цифр в дробной части
- left - выравнивание по левой границе
- right - выравнивание по правой границе
- boolalpha - вывод логических значений в текстовом виде
- nobool alpha - вывод логических значений в числовом виде
- dec - десятичная система счисления
- oct - восьмеричная система счисления
- hex - шестнадцатиричная система счисления
- showbase - показывать признак системы счисления
- noshowbase - не показывать признак системы счисления
- showpos - выводить + для положительных чисел
- noshowpos - не выводить + для положительных чисел
- sceintific - экспоненциальная форма для вещественных чисел
- fixed - фиксированная форма
- setfill() - установить символ заполнитель пустых элементов поля
Ввод-вывод и безопасность
При использовании классов в пространстве имен System.IO необходимо выполнить требования безопасности операционной системы, такие как списки управления доступом для контроля доступа к файлам и каталогам. Это требование дополняет остальные требования FileIOPermission. Списками управления доступом можно управлять программно. Дополнительные сведения см. в разделе Практическое руководство. Добавление или удаление записей списка управления доступом.
Проверка безопасности выполняется только при создании потока. Поэтому не рекомендуется открывать поток, а затем передавать его коду с меньшим уровнем доверия или доменам приложений.
См. также
Распространенные задачи ввода-вывода
Содержит список задач ввода-вывода, связанных с файлами, каталогами и потоками, а также ссылки на соответствующее содержимое и примеры для каждой задачи.
Асинхронный файловый ввод-вывод
Описывает преимущества и основные операции асинхронного ввода и вывода.
Изолированное хранилище
Описывает механизм хранения данных, обеспечивающий автономность и безопасность путем определения стандартизованных способов сопоставления кода с защищенными данными.
Сопоставленные в памяти файлы
Описание отображаемых в память файлов, позволяющих разместить содержимое файлов с диска в виртуальной памяти. С их помощью можно вносить изменения в очень большие файлы и создавать совместно используемую память для межпроцессного взаимодействия.
Поток — это последовательность байтов. В файловой системе NTFS потоки содержат данные, которые записываются в файл и предоставляют дополнительные сведения о файле, чем атрибуты и свойства. Например, можно создать поток, содержащий ключевые слова поиска, или удостоверение учетной записи пользователя, которая создает файл.
Каждый поток, связанный с файлом, имеет свой собственный размер выделения, фактический размер и допустимую длину данных:
- Размер выделения — это объем места на диске, зарезервированный для потока.
- Фактический размер — это число байтов, используемых вызывающим объектом.
- Допустимая длина данных (ВДЛ) — это число байтов, инициализированных из размера выделения для потока.
Каждый поток также сохраняет свое собственное состояние для сжатия, шифрования и разреженности. Атрибут _ _ разреженного _ файла атрибута file задается в элементе двфилеаттрибутес структуры _ _ данных Win32 Find , возвращаемой функциями FindFirstFile, финдфирстфиликси FindNextFile , если любой из потоков когда-либо был разреженным. GetFileAttributes, сбой getfileattributesex, жетфилеаттрибутестрансактед, жетфилеинформатионбихандлеи жетфилеинформатионбихандликс возвращают разреженное состояние потока данных по умолчанию, если поток не указан.
Нет файлов со временем, связанных с потоком. Время файла для файла обновляется при обновлении любого потока в файле.
Для каждого потока поддерживается оппортунистическая блокировка. Режимы совместного использования также поддерживаются для каждого потока. Когда для файла запрашивается доступ на удаление, операционная система проверяет доступ на удаление всех открытых потоков в файле. Если другой процесс открыл поток без разрешения на _ _ удаление файлового ресурса , открыть его для удаления доступа нельзя.
Если копируемый файл содержит поток данных и используется перенаправитель сети, то файл можно скопировать только в том случае, если у клиента есть разрешение на чтение и чтение атрибутов.
Содержание
Процесс взаимодействия с пользователем выполняется в терминах записи и чтения в файл. То есть вывод на экран представляется как запись в файл, а ввод — как чтение файла. Файл, из которого осуществляется чтение, называется стандартным потоком ввода, а в который осуществляется запись — стандартным потоком вывода.
Стандартные потоки привязаны к файловым дескрипторам с номерами 0, 1 и 2.
- Стандартный поток ввода (stdin) — 0;
- Стандартный поток вывода (stdout) — 1;
- Стандартный поток ошибок (stderr) — 2.
Вывод данных на экран и чтение их с клавиатуры происходит потому, что по умолчанию стандартные потоки ассоциированы с терминалом пользователя. Это не является обязательным — потоки можно подключать к чему угодно — к файлам, программам и даже устройствам. В командном интерпретаторе bash такая операция называется перенаправлением.
Весь текст между блоками EOF (в общем случае вместо EOF можно использовать любое слово) будет выведен на экран. Важно: перед последним EOF не должно быть пробелов! (heredoc синтаксис).
Пример. Эта команда объединяет три файла: header, body и footer в один файл letter:
Команда cat по очереди выводит содержимое файлов, перечисленных в качестве параметров на стандартный поток вывода. Стандартный поток вывода перенаправлен в файл letter.
Здесь используется сразу перенаправление стандартного потока ввода и стандартного потока вывода:
Программа sort сортирует данные, поступившие в стандартный поток ввода, и выводит их на стандартный поток вывода. Стандартный поток ввода подключен к файлу unsortedlines, а выход записывается в sortedlines.
Здесь перенаправлены потоки вывода и ошибок:
Для того чтобы лучше понять, что потоки работают как файлы, рассмотрим такой пример:
Программа cat запускается для записи данных в файл /tmp/fff. Он запускается в фоне (&), и получает номер работы 1 ([1]). Процесс этой программы имеет номер 28378.
Информация о процессе 28738 находится в каталоге /proc/28738 специальной псевдофайловой системы /proc. В частности, в подкаталоге /proc/28738/fd/ находится список файловых дескрипторов для открытых процессом файлов.
Здесь видно, что стандартный поток ввода (0), и стандартный поток ошибок (2) процесса подключены на терминал, а вот стандартный поток вывода (1) перенаправлен в файл.
Завершить работу программы cat можно командой kill %1.
Командный интерпретатор — это тоже процесс. И у него есть стандартные потоки ввода и вывода. Если интерпретатор работает в интерактивном режиме, то они подключены на консоль (вывода на экран; чтение с клавиатуры). Можно обратиться напрямую к этим потокам изнутри интерпретатора:
- /dev/stdin — стандартный поток ввода;
- /dev/stdout — стандартный поток вывода;
- /dev/stderr — стандартный поток ошибок.
Например, здесь видно, что потоки ссылаются в конечном итоге на файл-устройство терминала, с которым работает интерпретатор:
Стандартные потоки можно перенаправлять не только в файлы, но и на вход других программ. Если поток вывода одной программы соединить с потоком ввода другой программы, получится конструкция, называемая каналом, конвейером или пайпом (от англ. pipe, труба).
В bash канал выглядит как последовательность команд, отделенных друг от друга символом |:
команда1 | команда2 | команда3 .
Стандартный поток вывода команды1 подключается к стандартному потоку ввода команды2, стандартный поток вывода команды2 в свою очередь подключается к потоку ввода команды3 и т.д.
В UNIX/Linux существует целый класс команд, предназначенных для преобразования потоков данных в каналах. Такие программы известны как фильтры. Программа-фильтр читает данные, поступающие со стандартного потока ввода (на вход), преобразовывает их требуемым образом и выводит на стандартный поток вывода (на выход). Существует множество хорошо известных фильтров, призванных решать определенные задачи, и являющихся незаменимым инструментом в руках пользователя ОС.
Каналы в ОС Linux являются одной из наиболее часто применяемых конструкций, а фильтры — наиболее часто применяемых программ. Большинство повседневных задач в Linux легко решаются при помощи конструкций построенных на основе нескольких фильтров.
Программы, образующие канал, выполняются параллельно как независимые процессы.
Можно создавать ответвление в каналах. Команда tee позволяет сохранять данные, передающиеся в канале:
tee [опции] файл
Программа tee копирует данные, поступающие на стандартный поток ввода, в указанные в качестве аргументов команды файлы, и передает данные на стандартный поток вывода.
Рассмотренный ниже пример: сортируется файл unsortedlines и результат записывается в sortedlines.
Команда выполняет те же действия, но запись является более наглядной.
Вот пример посложнее. Вывести название и размер пользовательского каталога, занимающее наибольшее место на диске.
Программа du, при вызове ее с ключом -s, сообщает суммарный объем каждого каталога или файла, перечисленного в ее параметрах.
Ключ -n команды sort означает, что сортировка должна быть арифметической, т.е. строки должны рассматриваться как числа, а не как последовательности символов (Например, 12>5 в то время как строка '12'-r означает изменения порядка сортировки — с возрастающего на убывающий.
Команда head выводит несколько первых строк поступающего на ее вход потока, отбрасывая все остальные. Ключ -1 означает, что надо вывести только одну строку.
Таким образом, список пользовательских каталогов с их суммарным объемом арифметически сортируется по убыванию, и из полученного списка берется первая строка, т.е. строка с наибольшим числом, соответствующая самому объемному каталогу.
Использование команды tee:
Содержимое файла text сортируется, и результат сортировки записывается в файл sorted_text. Первая строка отсортированного текста выдается на экран.
В UNIX/Linux существует целый класс команд, которые принимают данные со стандартного потока ввода, каким-то образом обрабатывают их, и выдают результат на стандартный поток вывода. Такие программы называются программами-фильтрами.
Как правило, все эти программы работают как фильтры, если у них нет аргументов (опции могут быть), но как только им в качестве аргумента передаётся файл, они считывают данные из этого файла, а не со стандартного потока ввода (существуют и исключения, например, программа tr, которая обрабатывает данные поступающие исключительно через стандартный поток ввода).
sh -s Текст, который передаётся на стандартный поток ввода sh -s может интерпретироваться как последовательность команд shell. На выход передаётся результат их исполнения. ssh Средство удалённого доступа ssh, может работать как фильтр. ssh подхватывает данные, переданные ему на стандартный поток ввода, передаёт их на удалённых хост и подаёт на вход процессу программы, имя которой было передано ему в качестве аргумента. Результат выполнения программы (то есть то, что она выдала на стандартный поток вывода) передаётся со стандартного вывода ssh.
Для того чтобы вывести содержимое переменной командного интерпретатора на стандартный поток вывода, используется команда echo:
На стандартный поток ошибок данные можно передать с помощью перенаправления:
Содержимое переменной (или любой другой текст) поступят не на стандартный поток вывода, а на стандартный поток ошибок.
Считать данные со стандартного потока ввода внутрь одной или нескольких переменных можно при помощи команды read:
Строка из стандартного потока ввода считается внутрь переменной VAR.
Если указать несколько переменных, то в первую попадёт первое слово; во вторую — второе слово; в последнюю — всё остальное.
Обратите внимание на конструкцию read VAR; echo $VAR >. Переменная считанная из канала с помощью read будет доступна только внутри < >. Например echo text | read var; echo $var выведет пустое место. Это связано с тем, что для перенаправления внутрь read shell порождает дочерний процесс, в котором и исполняет read. Переменная дочернего процесса не передаётся наружу. (Внимание. В zsh всё работает и без этих костылей).
Если прочитать данные со стандартного потока ввода не удалось, то команда read возвращает код завершения отличный от нуля. Это позволяет использовать read, например, в такой конструкции:
В этом примере read считывает строки из файла users, и для каждой прочитанной строки вызывается команда useradd, которая добавляет пользователя в системе. В результате: создаются учётные записи пользователей, имена которых перечислены в файле users.
Переменная user после выхода из цикла остаётся в том же виде, в каком она была до входа в цикл (а не содержит последнее значение файла, как можно было бы предположить). Это связано с тем, что для обработки while, на вход которому направлен канал, порождается дочерний интерпретатор, и модификация переменной происходит внутри него.
Безымянный канал можно построить только между процессами, которые порождены от одного процесса (и на практике они должны быть порождены одновременно, а не последовательно, хотя теоретически это не обязательно). Если же процессы имеют разных родителей, то между ними обычный, безымянный канал построить не получится.
Например, в данном случае d и e, и f и g легко могут быть соединены при помощи канала, но e и f соединить с помощью канала не получится.
Для решения этой задачи используются именованные каналы fifo (first in, first out). Они во всём повторяют обычные каналы (pipe), только имеют привязку к файловой системе. Создать именованный канал можно командой mkfifo:
Созданный канал можно использовать для соединения процессов между собой. Например, эти перенаправления будут работать одинаково:
(здесь f и g — процессы из вышеуказанной иерархии процессов). Процессы f и g имеют общего предка. А вот для процессов e и g, не связанных между собой, обычный канал использовать не получится, только именованный:
Большинство программ, которые работают с потоками ввода и вывода, работают с ними как с простыми файлами, и не рассчитывают на то, что поток подключен к терминалу. Но не все. Если потоки ввода/вывода отключаются от терминала и перенаправляются в файл, часть возможностей программы может пропасть.
Например, если командный интерпретатор отвязать от терминала, то у него потеряется множество интерактивных возможностей:
Например, возможности прокручивать историю команд у него теперь нет. Возможности по редактированию теперь тоже сильно урезаны. Фактически, редактирование команды теперь выполняется уже с помощью программы cat, которая держит терминал, а интерпретатору поступают уже полностью введённые команды.
Проверить, подключен ли наш стандартный поток к терминалу, или он перенаправлен в файл, можно при помощи test, ключ -t:
Есть хитрый трюк, который в чистом виде перенаправлением потока ввода/вывода не является, но имеет к нему отношение — подстановка процесса. Результат выполнения процесса можно представить в виде воображаемого файла и передать его другому процессу.
При таком вызове процессу команда1 передаётся файл (созданный налету канал или файл /dev/fd/. ), в котором находятся данные, которые выводит команда2.
Например, у вас есть два файла с различными словами по одному в строке. Вы хотите определить, какие из них встречаются в одном файле, но не встречаются во втором. И наоборот.
Получается, что в первом файле присутствует слово, которое отсутствует во втором (слово b).
Потоки ввода/вывода скрипта, исполняющегося сейчас, изнутри самого скрипта можно следующим образом:
Если пропустить данные, передающиеся в канале, через программу pv, то будет видна скорость обработки, время в течение которого работает канал и, если известно сколько данных должно быть обработано, приблизительное время окончания выполнения.
Изолированное хранилище
Изолированное хранилище — это механизм хранения данных, обеспечивающий изоляцию и безопасность путем определения стандартизованных способов сопоставления кода с хранимыми данными. Хранилище предоставляет виртуальную файловую систему, изолированную по пользователю, сборке и (необязательно) домену. Изолированное хранилище особенно полезно в том случае, когда приложение не имеет разрешения на доступ к файлам пользователя. Можно сохранить параметры или файлы для приложения таким способом, который контролируется политикой безопасности компьютера.
Изолированное хранилище недоступно для приложений Microsoft Store для Windows 8.x. Вместо этого используйте классы данных приложения в пространстве имен Windows.Storage. Дополнительные сведения см. в разделе Данные приложения.
Часто используются следующие классы, реализующие изолированное хранилище:
IsolatedStorage предоставляет базовый класс для реализации изолированного хранилища.
IsolatedStorageFile предоставляет область изолированного хранилища, в которой содержатся файлы и каталоги.
IsolatedStorageFileStream представляет файл в изолированном хранилище.
Средства чтения и записи
Пространство имен System.IO также предоставляет типы для чтения закодированных символов из потоков и их записи в потоки. Как правило, потоки предназначены для ввода и вывода байтов. Типы чтения и записи обрабатывают преобразование закодированных символов в байты или из байтов, чтобы поток мог завершить операцию. Каждый класс чтения и записи связан с потоком, который можно получить с помощью свойства класса BaseStream .
Ниже перечислены некоторые часто используемые классы для чтения и записи:
BinaryReader и BinaryWriter — для чтения и записи простых типов данных, таких как двоичные значения.
StreamReader и StreamWriter — для чтения и записи символов с использованием закодированного значения для преобразования символов в байты или из байтов.
StringReader и StringWriter — для чтения и записи символов в строки или из строк.
TextReader и TextWriter используются в качестве абстрактных базовых классов для других средств чтения и записи, которые считывают и записывают символы и строки, а не двоичные данные.
соглашения об именовании для Потоки
при указании из командной строки оболочки Windows полное имя потока — "имя_файла:поток имя:тип потока", как показано в следующем примере: "myfile. dat: stream1: $DATA".
Все символы, допустимые для имени файла, также являются допустимыми для имени потока, включая пробелы. Дополнительные сведения см. в разделе Присвоение имени файлу. Тип потока (также называемый кодом типа атрибута) является внутренним для файловой системы NTFS. Поэтому пользователи не могут создавать новые типы потоков, но могут открывать существующие типы файловой системы NTFS. Значения спецификатора типа потока всегда начинаются с символа доллара ($). Список типов потоков см. ниже.
По умолчанию поток данных не имеет имени. Чтобы полностью указать поток данных по умолчанию, используйте "filename:: $Data", где $Data является типом потока. Это эквивалентно "filename". В файле можно создать именованный поток, используя соглашения об именовании файлов. Обратите внимание, что "$DATA" является допустимым именем потока. Например, полное имя потока с именем "$DATA" для файла "Sample" будет иметь вид "Sample: $data: $Data". Если вы создали поток с именем "Bar" для того же файла, его полное имя будет иметь вид "Пример: линейчатая диаграмма: $Data".
При создании и работе с файлами, имеющими имена из одного символа, добавляйте к имени файла с точкой, за которой следует обратная косая черта (. ) или используйте полное имя пути. причина этого заключается в том, что Windows воспринимает имена файлов одного символа как буквы диска. Если буква диска указана с помощью относительного пути, двоеточие отделяет букву диска от пути. при неоднозначности того, является ли односимвольное имя буквой диска или именем файла, Windows предполагает, что это буква диска, если строка, следующая за двоеточием, является допустимым путем, даже если буква диска является недопустимой.
Асинхронные операции ввода-вывода
Чтение и запись больших объемов данных может быть ресурсоемкой. Эти задачи необходимо выполнять асинхронно, если приложение должно продолжать отвечать на запросы пользователя. В случае синхронных операций ввода-вывода поток пользовательского интерфейса будет заблокирован до тех пор, пока ресурсоемкая операция не завершится. При разработке приложений Microsoft Store для Windows 8.x используйте асинхронные операции ввода-вывода, чтобы не создавалось впечатления, что приложение прекратило свою работу.
Асинхронные члены содержат Async имена, такие как CopyToAsync методы, FlushAsyncReadAsync , и WriteAsync . Используйте эти методы с ключевыми словами async и await .
Дополнительные сведения см. в разделе Асинхронный файловый ввод-вывод.
Типы потоков
Ниже приведен список типов потоков NTFS, которые также называются кодами типов атрибутов. Некоторые типы потоков являются внутренними для файловой системы NTFS, и их формат не является документом.
Работа с файлами с использованием конструкций языка Си была рассмотрена здесь.
Для программиста открытый файл представляется как последовательность считываемых или записываемых данных. При открытии файла с ним связывается поток ввода-вывода . Выводимая информация записывается в поток, вводимая информация считывается из потока.
Для работы с файлами необходимо подключить заголовочный файл . В нем определены несколько классов и подключены заголовочные файлы
Файловый ввод-вывод аналогичен стандартному вводу-выводу, единственное отличие – это то, что ввод-вывод выполнятся не на экран, а в файл.
Если ввод-вывод на стандартные устройства выполняется с помощью объектов cin и cout , то для организации файлового ввода-вывода достаточно создать собственные объекты, которые можно использовать аналогично этим операторам.
При работе с файлом можно выделить следующие этапы:
- создать объект класса fstream (возможно, ofstream или ifstream );
- связать объект класса fstream с файлом, который будет использоваться для операций ввода-вывода;
- осуществить операции ввода-вывода в файл;
- закрыть файл.
В результате будет создан файл
Режимы открытия файлов устанавливают характер использования файлов. Для установки режима в классе ios предусмотрены константы, которые определяют режим открытия файлов.
Константа | Описание |
ios::in | открыть файл для чтения |
ios::out | открыть файл для записи |
ios::ate | при открытии переместить указатель в конец файла |
ios::app | открыть файл для записи в конец файла |
ios::trunc | удалить содержимое файла, если он существует |
ios::binary | открытие файла в двоичном режиме |
Режимы открытия файлов можно устанавливать непосредственно при создании объекта или при вызове метода open() .
Режимы открытия файлов можно комбинировать с помощью поразрядной логической операции ИЛИ | , например:
ios::out | ios::in - открытие файла для записи и чтения.
Сжатие
При сжатии и распаковке файлов и потоков часто используются следующие классы:
ZipArchive — для создания и восстановления содержимого ZIP-архива.
ZipArchiveEntry — для представления сжатого файла.
ZipFile — для создания, извлечения и открытия сжатого пакета.
ZipFileExtensions — для создания и извлечения содержимого из сжатого пакета.
DeflateStream — для сжатия и распаковки потоков с помощью алгоритма Deflate.
GZipStream — для сжатия и распаковки потоков в формате gzip.
См. практическое руководство по Сжатие и извлечение файлов.
Читайте также: