Работа с файлами в С++
Большинство компьютерных программ работают с файлами, и поэтому возникает необходимость создавать, удалять, записывать читать, открывать файлы. Что же такое файл? Файл – именованный набор байтов, который может быть сохранен на некотором накопителе. Ну, теперь ясно, что под файлом понимается некоторая последовательность байтов, которая имеет своё, уникальное имя, например файл.txt . В одной директории не могут находиться файлы с одинаковыми именами. Под именем файла понимается не только его название, но и расширение, например: file.txt и file.dat — разные файлы, хоть и имеют одинаковые названия. Существует такое понятие, как полное имя файлов – это полный адрес к директории файла с указанием имени файла, например: D:\docs\file.txt . Важно понимать эти базовые понятия, иначе сложно будет работать с файлами.
Для работы с файлами необходимо подключить заголовочный файл <fstream> . В <fstream> определены несколько классов и подключены заголовочные файлы <ifstream> — файловый ввод и <ofstream> — файловый вывод.
Файловый ввод/вывод аналогичен стандартному вводу/выводу, единственное отличие – это то, что ввод/вывод выполнятся не на экран, а в файл. Если ввод/вывод на стандартные устройства выполняется с помощью объектов cin и cout , то для организации файлового ввода/вывода достаточно создать собственные объекты, которые можно использовать аналогично операторам cin и cout .
Например, необходимо создать текстовый файл и записать в него строку Работа с файлами в С++ . Для этого необходимо проделать следующие шаги:
- создать объект класса ofstream ;
- связать объект класса с файлом, в который будет производиться запись;
- записать строку в файл;
- закрыть файл.
Почему необходимо создавать объект класса ofstream , а не класса ifstream ? Потому, что нужно сделать запись в файл, а если бы нужно было считать данные из файла, то создавался бы объект класса ifstream .
Назовём объект – fout , Вот что получится:
Для чего нам объект? Объект необходим, чтобы можно было выполнять запись в файл. Уже объект создан, но не связан с файлом, в который нужно записать строку.
Через операцию точка получаем доступ к методу класса open(), в круглых скобочках которого указываем имя файла. Указанный файл будет создан в текущей директории с программой. Если файл с таким именем существует, то существующий файл будет заменен новым. Итак, файл открыт, осталось записать в него нужную строку. Делается это так:
Используя операцию передачи в поток совместно с объектом fout строка Работа с файлами в С++ записывается в файл. Так как больше нет необходимости изменять содержимое файла, его нужно закрыть, то есть отделить объект от файла.
Итог – создан файл со строкой Работа с файлами в С++ .
Шаги 1 и 2 можно объединить, то есть в одной строке создать объект и связать его с файлом. Делается это так:
Объединим весь код и получим следующую программу.
Осталось проверить правильность работы программы, а для этого открываем файл cppstudio.txt и смотрим его содержимое, должно быть — Работа с файлами в С++ .
Для того чтобы прочитать файл понадобится выполнить те же шаги, что и при записи в файл с небольшими изменениями:
- создать объект класса ifstream и связать его с файлом, из которого будет производиться считывание;
- прочитать файл;
- закрыть файл.
В программе показаны два способа чтения из файла, первый – используя операцию передачи в поток, второй – используя функцию getline() . В первом случае считывается только первое слово, а во втором случае считывается строка, длинной 50 символов. Но так как в файле осталось меньше 50 символов, то считываются символы включительно до последнего. Обратите внимание на то, что считывание во второй раз ( строка 17 ) продолжилось, после первого слова, а не с начала, так как первое слово было прочитано в строке 14 . Результат работы программы показан на рисунке 1.
Рисунок 1 — Работа с файлами в С++
Программа сработала правильно, но не всегда так бывает, даже в том случае, если с кодом всё впорядке. Например, в программу передано имя несуществующего файла или в имени допущена ошибка. Что тогда? В этом случае ничего не произойдёт вообще. Файл не будет найден, а значит и прочитать его не возможно. Поэтому компилятор проигнорирует строки, где выполняется работа с файлом. В результате корректно завершится работа программы, но ничего, на экране показано не будет. Казалось бы это вполне нормальная реакции на такую ситуацию. Но простому пользователю не будет понятно, в чём дело и почему на экране не появилась строка из файла. Так вот, чтобы всё было предельно понятно в С++ предусмотрена такая функция — is_open() , которая возвращает целые значения: 1 — если файл был успешно открыт, 0 — если файл открыт не был. Доработаем программу с открытием файла, таким образом, что если файл не открыт выводилось соответствующее сообщение.
Результат работы программы показан на рисунке 2.
Рисунок 2 — Работа с файлами в С++
Как видно из рисунка 2 программа сообщила о невозможности открыть файл. Поэтому, если программа работает с файлами, рекомендуется использовать эту функцию, is_open() , даже, если уверены, что файл существует.
Режимы открытия файлов
Режимы открытия файлов устанавливают характер использования файлов. Для установки режима в классе ios_base предусмотрены константы, которые определяют режим открытия файлов (см. Таблица 1).
| Константа | Описание |
|---|---|
| ios_base::in | открыть файл для чтения |
| ios_base::out | открыть файл для записи |
| ios_base::ate | при открытии переместить указатель в конец файла |
| ios_base::app | открыть файл для записи в конец файла |
| ios_base::trunc | удалить содержимое файла, если он существует |
| ios_base::binary | открытие файла в двоичном режиме |
Режимы открытия файлов можно устанавливать непосредственно при создании объекта или при вызове функции open() .
Режимы открытия файлов можно комбинировать с помощью поразрядной логической операции или | , например: ios_base::out | ios_base::trunc — открытие файла для записи, предварительно очистив его.
Объекты класса ofstream , при связке с файлами по умолчанию содержат режимы открытия файлов ios_base::out | ios_base::trunc . То есть файл будет создан, если не существует. Если же файл существует, то его содержимое будет удалено, а сам файл будет готов к записи. Объекты класса ifstream связываясь с файлом, имеют по умолчанию режим открытия файла ios_base::in — файл открыт только для чтения. Режим открытия файла ещё называют — флаг, для удобочитаемости в дальнейшем будем использовать именно этот термин. В таблице 1 перечислены далеко не все флаги, но для начала этих должно хватить.
Обратите внимание на то, что флаги ate и app по описанию очень похожи, они оба перемещают указатель в конец файла, но флаг app позволяет производить запись, только в конец файла, а флаг ate просто переставляет флаг в конец файла и не ограничивает места записи.
Разработаем программу, которая, используя операцию sizeof() , будет вычислять характеристики основных типов данных в С++ и записывать их в файл. Характеристики:
- число байт, отводимое под тип данных
- максимальное значение, которое может хранить определённый тип данных.
Запись в файл должна выполняться в таком формате:
Такая программа уже разрабатывалась ранее в разделе Типы данных С++ , но там вся информация о типах данных выводилась на стандартное устройство вывода, а нам необходимо программу переделать так, чтобы информация записывалась в файл. Для этого необходимо открыть файл в режиме записи, с предварительным усечением текущей информации файла (строка 14). Как только файл создан и успешно открыт (строки 16 — 20), вместо оператора cout , в строке 22 используем объект fout . таким образом, вместо экрана информация о типах данных запишется в файл.
Нельзя не заметить, что изменения в программе минимальны, а всё благодаря тому, что стандартный ввод/вывод и файловый ввод/вывод используются абсолютно аналогично. В конце программы, в строке 45 мы явно закрыли файл, хотя это и не обязательно, но считается хорошим тоном программирования. Стоит отметить, что все функции и манипуляторы используемые для форматирования стандартного ввода/вывода актуальны и для файлового ввода/вывода. Поэтому не возникло никаких ошибок, когда оператор cout был заменён объектом fout .
Как вывести данные из файла с
Класс FileStream представляет возможности по считыванию из файла и записи в файл. Он позволяет работать как с текстовыми файлами, так и с бинарными.
Создание FileStream
Для создания объекта FileStream можно использовать как конструкторы этого класса, так и статические методы класса File. Конструктор FileStream имеет множество перегруженных версий, из которых отмечу лишь одну, самую простую и используемую:
Здесь в конструктор передается два параметра: путь к файлу и перечисление FileMode . Данное перечисление указывает на режим доступа к файлу и может принимать следующие значения:
Append : если файл существует, то текст добавляется в конец файл. Если файла нет, то он создается. Файл открывается только для записи.
Create : создается новый файл. Если такой файл уже существует, то он перезаписывается
CreateNew : создается новый файл. Если такой файл уже существует, то приложение выбрасывает ошибку
Open : открывает файл. Если файл не существует, выбрасывается исключение
OpenOrCreate : если файл существует, он открывается, если нет — создается новый
Truncate : если файл существует, то он перезаписывается. Файл открывается только для записи.
Другой способ создания объекта FileStream представляют статические методы класса File:
Первый метод открывает файл с учетом объекта FileMode и возвращает файловой поток FileStream. У этого метода также есть несколько перегруженных версий. Второй метод открывает поток для чтения, а третий открывает поток для записи.
Закрытие потока
Класс FileStream для освобождения всех реусрсов, связанных с файлом, реализует интерфейс IDisposable. Соответственно после завершения работы с FileStream необходимо освободить связанный с ним файл вызовом метода Dispose. Для корректного закрытия можно вызвать метод Close() , который вызывает метод Dispose:
Либо можно использовать конструкцию using, которая автоматически освободит все связанные с FileStream ресурсы:
Свойства и методы FileStream
Рассмотрим наиболее важные свойства класса FileStream :
Свойство Length : возвращает длину потока в байтах
Свойство Position : возвращает текущую позицию в потоке
Свойство Name : возвращает абсолютный путь к файлу, открытому в FileStream
Для чтения/записи файлов можно применять следующие методы класса FileStream :
void CopyTo(Stream destination) : копирует данные из текущего потока в поток destination
Task CopyToAsync(Stream destination) : асинхронная версия метода CopyTo
void Flush() : сбрасывает содержимое буфера в файл
Task FlushAsync() : асинхронная версия метода Flush
int Read(byte[] array, int offset, int count) : считывает данные из файла в массив байтов и возвращает количество успешно считанных байтов. Принимает три параметра:
array — массив байтов, куда будут помещены считываемые из файла данные
offset представляет смещение в байтах в массиве array, в который считанные байты будут помещены
count — максимальное число байтов, предназначенных для чтения. Если в файле находится меньшее количество байтов, то все они будут считаны.
Task<int> ReadAsync(byte[] array, int offset, int count) : асинхронная версия метода Read
long Seek(long offset, SeekOrigin origin) : устанавливает позицию в потоке со смещением на количество байт, указанных в параметре offset.
void Write(byte[] array, int offset, int count) : записывает в файл данные из массива байтов. Принимает три параметра:
array — массив байтов, откуда данные будут записываться в файл
offset — смещение в байтах в массиве array, откуда начинается запись байтов в поток
count — максимальное число байтов, предназначенных для записи
Чтение и запись файлов
FileStream представляет доступ к файлам на уровне байтов, поэтому, например, если вам надо считать или записать одну или несколько строк в текстовый файл, то массив байтов надо преобразовать в строки, используя специальные методы. Поэтому для работы с текстовыми файлами применяются другие классы.
В то же время при работе с различными бинарными файлами, имеющими определенную структуру, FileStream может быть очень даже полезен для извлечения определенных порций информации и ее обработки.
Посмотрим на примере считывания-записи в текстовый файл:
Разберем этот пример. Вначале определяем путь к файлу и текст для записи в файл.
И при чтении, и при записи для создания и удаления объекта FileStream используется конструкция using , по завершению которой у созданного объекта FileStream автоматически вызывается метод Dispose , и, таким образом, объект уничтожается.
Поскольку операции с файлами могут занимать продолжительное время и являются узким местом в работе программы, рекомендуется использовать асинхронные версии методов FileStream. И при записи, и при чтении применяется объект кодировки Encoding.Default из пространства имен System.Text . В данном случае мы используем два его метода: GetBytes для получения массива байтов из строки и GetString для получения строки из массива байтов.
В итоге введенная нами строка записывается в файл note.txt . И мы получим следующий консольный вывод:
Записанный файл по сути представляет бинарный файл (не текстовый), хотя если мы в него запишем только строку, то сможем посмотреть в удобочитаемом виде этот файл, открыв его в текстовом редакторе. Однако если мы в него запишем случайные байты, например:
То у нас могут возникнуть проблемы с его пониманием. Поэтому для работы непосредственно с текстовыми файлами предназначены отдельные классы — StreamReader и StreamWriter.
Произвольный доступ к файлам
Нередко бинарные файлы представляют определенную структуру. И, зная эту структуру, мы можем взять из файла нужную порцию информации или наоброт записать в определенном месте файла определенный набор байтов. Например, в wav-файлах непосредственно звуковые данные начинаются с 44 байта, а до 44 байта идут различные метаданные — количество каналов аудио, частота дискретизации и т.д.
С помощью метода Seek() мы можем управлять положением курсора потока, начиная с которого производится считывание или запись в файл. Этот метод принимает два параметра: offset (смещение) и позиция в файле. Позиция в файле описывается тремя значениями:
SeekOrigin.Begin : начало файла
SeekOrigin.End : конец файла
SeekOrigin.Current : текущая позиция в файле
Курсор потока, с которого начинается чтение или запись, смещается вперед на значение offset относительно позиции, указанной в качестве второго параметра. Смещение может быть отрицательным, тогда курсор сдвигается назад, если положительное — то вперед.
Рассмотрим простой пример:
Вначале записываем в файл текст «hello world». Затем снова обращаемся к файла для считывания. Сначала перемещаем курсор на пять символов назад относительно конца файлового потока:
То есть после выполнения этого вызова курсор будет стоять на позиции символа «w».
После этого считываем пять байт начиная с символа «w». В кодировке по умолчанию 1 символ будет представлять 1 байт. Поэтому чтение 5 байт будет эквивалентно чтению пяти сиволов: «world».
Соответственно мы получим следующий консольный вывод:
Рассмотрим чуть более сложный пример — с записью начиная с некоторой позиции:
Здесь также вначале записываем в файл строку «hello world». Затем также открываем файл и опять же перемещаемся в конец файла, не доходя до конца пять символов (то есть опять же с позиции символа «w»), и осуществляем запись строки «house». Таким образом, строка «house» заменяет строку «world».
Работа с файлами
Для удобства обращения информация в запоминающих устройствах хранится в виде файлов.
Файл – именованная область внешней памяти, выделенная для хранения массива данных. Данные, содержащиеся в файлах, имеют самый разнообразный характер: программы на алгоритмическом или машинном языке; исходные данные для работы программ или результаты выполнения программ; произвольные тексты; графические изображения и т. п.
Каталог ( папка , директория ) – именованная совокупность байтов на носителе информации, содержащая название подкаталогов и файлов, используется в файловой системе для упрощения организации файлов.
Файловой системой называется функциональная часть операционной системы, обеспечивающая выполнение операций над файлами. Примерами файловых систем являются FAT (FAT – File Allocation Table, таблица размещения файлов), NTFS, UDF (используется на компакт-дисках).
Существуют три основные версии FAT: FAT12, FAT16 и FAT32. Они отличаются разрядностью записей в дисковой структуре, т.е. количеством бит, отведённых для хранения номера кластера. FAT12 применяется в основном для дискет (до 4 кбайт), FAT16 – для дисков малого объёма, FAT32 – для FLASH-накопителей большой емкости (до 32 Гбайт).
Рассмотрим структуру файловой системы на примере FAT32.
Файловая структура FAT32
Устройства внешней памяти в системе FAT32 имеют не байтовую, а блочную адресацию. Запись информации в устройство внешней памяти осуществляется блоками или секторами.
Сектор – минимальная адресуемая единица хранения информации на внешних запоминающих устройствах. Как правило, размер сектора фиксирован и составляет 512 байт. Для увеличения адресного пространства устройств внешней памяти сектора объединяют в группы, называемые кластерами.
Кластер – объединение нескольких секторов, которое может рассматриваться как самостоятельная единица, обладающая определёнными свойствами. Основным свойством кластера является его размер, измеряемый в количестве секторов или количестве байт.
Файловая система 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 ).
Таблица FAT содержит информацию о состоянии каждого кластера на диске. Младшие 2 байт таблицы FAT хранят F8 FF FF 0F FF FF FF FF (что соответствует состоянию кластеров 0 и 1, физически отсутствующих). Далее состояние каждого кластера содержит номер кластера, в котором продолжается текущий файл или следующую информацию:
- 00 00 00 00 – кластер свободен;
- FF FF FF 0F – конец текущего файла.
Корневой каталог содержит набор 32-битных записей информации о каждом файле, содержащих следующую информацию:
- 8 байт – имя файла;
- 3 байта – расширение файла;
Корневой каталог содержит набор 32-битных записей информации о каждом файле, содержащих следующую информацию:
- 8 байт – имя файла;
- 3 байта – расширение файла;
- 1 байт – атрибут файла:

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

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

- 2 байта – дата последнего доступа;
- 2 байта – старшие 2 байта начального кластера;
- 2 байта – время последней модификации;
- 2 байта – дата последней модификации;
- 2 байта – младшие 2 байта начального кластера;
- 4 байта – размер файла (в байтах).
В случае работы с длинными именами файлов (включая русские имена) кодировка имени файла производится в системе кодировки UTF-16. При этого для кодирования каждого символа отводится 2 байта. При этом имя файла записывается в виде следующей структуры:
- 1 байт последовательности;
- 10 байт содержат младшие 5 символов имени файла;
- 1 байт атрибут;
- 1 байт резервный;
- 1 байт – контрольная сумма имени DOS;
- 12 байт содержат младшие 3 символа имени файла;
- 2 байта – номер первого кластера;
- остальные символы длинного имени.
Далее следует запись, включающая имя файла в формате 8.3 в обычном формате.
Работа с файлами в языке Си
Для программиста открытый файл представляется как последовательность считываемых или записываемых данных. При открытии файла с ним связывается поток ввода-вывода . Выводимая информация записывается в поток, вводимая информация считывается из потока.
Когда поток открывается для ввода-вывода, он связывается со стандартной структурой типа FILE , которая определена в stdio.h . Структура FILE содержит необходимую информацию о файле.
Открытие файла осуществляется с помощью функции fopen() , которая возвращает указатель на структуру типа FILE , который можно использовать для последующих операций с файлом.
- "r" — открыть файл для чтения (файл должен существовать);
- "w" — открыть пустой файл для записи; если файл существует, то его содержимое теряется;
- "a" — открыть файл для записи в конец (для добавления); файл создается, если он не существует;
- "r+" — открыть файл для чтения и записи (файл должен существовать);
- "w+" — открыть пустой файл для чтения и записи; если файл существует, то его содержимое теряется;
- "a+" — открыть файл для чтения и дополнения, если файл не существует, то он создаётся.
Возвращаемое значение — указатель на открытый поток. Если обнаружена ошибка, то возвращается значение NULL .
Функция fclose() закрывает поток или потоки, связанные с открытыми при помощи функции fopen() файлами. Закрываемый поток определяется аргументом функции fclose() .
Возвращаемое значение: значение 0, если поток успешно закрыт; константа EOF , если произошла ошибка.
Чтение символа из файла:
Аргументом функции является указатель на поток типа FILE . Функция возвращает код считанного символа. Если достигнут конец файла или возникла ошибка, возвращается константа EOF .
Запись символа в файл:
Аргументами функции являются символ и указатель на поток типа FILE . Функция возвращает код считанного символа.
Функции fscanf() и fprintf() аналогичны функциям scanf() и printf() , но работают с файлами данных, и имеют первый аргумент — указатель на файл.
Функции fgets() и fputs() предназначены для ввода-вывода строк, они являются аналогами функций gets() и puts() для работы с файлами.
Символы читаются из потока до тех пор, пока не будет прочитан символ новой строки ‘\n’ , который включается в строку, или пока не наступит конец потока EOF или не будет прочитано максимальное количество символов. Результат помещается в указатель на строку и заканчивается нуль- символом ‘\0’ . Функция возвращает адрес строки.
Результат выполнения — 2 файла
Работа с файлами в C++ описана здесь.
Программирование на C, C# и Java
Уроки программирования, алгоритмы, статьи, исходники, примеры программ и полезные советы
ОСТОРОЖНО МОШЕННИКИ! В последнее время в социальных сетях участились случаи предложения помощи в написании программ от лиц, прикрывающихся сайтом vscode.ru. Мы никогда не пишем первыми и не размещаем никакие материалы в посторонних группах ВК. Для связи с нами используйте исключительно эти контакты: vscoderu@yandex.ru, https://vk.com/vscode
Программа, которая выводит на экран содержимое файла
В этом уроке мы покажем, как средствами C# прочитать текстовый файл и вывести его содержимое на экран компьютера в консоль.
Сначала необходимо с помощью директивы using подключить пространство имен System.IO (в нем описан необходимый для данной задачи класс).
Теперь создадим экземпляр класса StreamReader. StreamReader — это класс который позволяет считывать символы из потока байтов в определенной кодировке. Инициализируем создаваемый экземпляр класса именем файла, из которого будем производить считывание текста.
Если указать просто имя файла без пути к нему (как в данном случае textfile.txt), то файл необходимо расположить в каталоге \bin\Debug\ вашего проекта. Если текстовый файл располагается в какой-либо другой папке, то необходимо указать к нему полный путь.
Объявим строковую переменную s. Она нам понадобится для хранения считанной строки.
Далее напишем такой код:
В цикле while происходит считывание файла построчно с помощью метода класса StreamReader ReadLine(), считанная строка присваивается строковой переменной s. С помощью оператора Console.WriteLine(s) считанная строка выводится в консоль.
Цикл while продолжается до тех пор, пока не будет достигнут конец файла.
Свойство EndOfStream указывается достигнут ли конец файла. Оно имеет логическое значение true, если конец файла достигнут, и логическое значение false в противном случае.
Последнее, что нужно сделать, это закрыть считывающий символьный поток из файла.
В итоге у вас должен получится следующий код:
Давайте протестируем написанную программу. Для этого запустим её. Нажмём в Visual Studio сочетание клавиш Ctrl + F5 (чтобы консоль не закрылась сразу после выполнения программы).

Как вы видите текст из файла успешно вывелся на экран компьютера в консоль.
Если вы хотите скачать исходник программы, написанной в этом уроке, то нажмите на кнопку ниже.
Поделиться в соц. сетях:
5 комментария(ев) к статье “ Программа, которая выводит на экран содержимое файла ”
Здравствуйте! Запустила Вашу программу. Вместо букв русского алфавита появляются вопросительные знаки. Почему так происходит и что делать?
- admin Автор статьи 17.02.2017 в 11:52
Здравствуйте! Проблема в кодировке.
Попробуйте использовать следующую строку:
StreamReader sr = new StreamReader(“textfile.txt”, Encoding.UTF8);
вместо StreamReader sr = new StreamReader(“textfile.txt”);
Если не сработает, то поменяйте UTF8 на какое-либо из следующих значений: ASCII, Default, Unicode, UTF7 или UTF32.
Спасибо!
Только при запуске программы (F5) появляется окно «Присоединиться к процессу» (могла бы присоединить screen shot, но некуда). Я, честно говоря, побоялась щелкнуть по кнопке Присоединиться, так как не понимаю, насколько это безопасно (не «поплывут» ли другие приложения?).
На всякий случай: VS установлено в папку Документы, так как у меня не было прав доступа администратора.