Как указать путь к файлу в c
У меня было так
Я открывал этот файл, при необходимости он создавался — и все было бы хорошо, но
И все больше файл открываться не хочет! (и не создается) Я больше ничего не менял в программе — значит виноваты эти строки. Подскажите, плиз.
| От: | LuciferMoscow |
| Дата: | 03.03.06 10:19 |
| Оценка: |
| От: | HiSH | http://m0riarty.ya.ru |
| Дата: | 03.03.06 10:21 | |
| Оценка: | 2 (2) | |
Здравствуйте, AlexDav, Вы писали:
AD>
AD>Я открывал этот файл, при необходимости он создавался — и все было бы хорошо, но
AD>Я заменил на
AD>
AD>И все больше файл открываться не хочет! (и не создается) Я больше ничего не менял в программе — значит виноваты эти строки. Подскажите, плиз.
А зачем двойные слеши? Должно быть или «c:\\program files\\. «, или «c:/program files/. «
| От: | rg45 |
| Дата: | 03.03.06 10:24 |
| Оценка: |
Здравствуйте, AlexDav, Вы писали:
AD>У меня было так
AD>
AD>Я открывал этот файл, при необходимости он создавался — и все было бы хорошо, но
AD>Я заменил на
AD>
AD>И все больше файл открываться не хочет! (и не создается) Я больше ничего не менял в программе — значит виноваты эти строки. Подскажите, плиз.
1. Либо «C://set.ds» либо «C:/set.ds» — двойной слэш — это лишний символ в строке, хотя большинством фунций «глотается» нормально.
2. Чтобы ответить, все таки, что не так, нужно видеть, как используется эта строка.
Вполне возможно, что проблема в пробелах, которые присутствуют во втором варианте и которых нет в первом.
| От: | AlexDav |
| Дата: | 03.03.06 10:27 |
| Оценка: |
Здравствуйте, HiSH, Вы писали:
HSH>А зачем двойные слеши? Должно быть или «c:\\program files\\. «, или «c:/program files/. «
Так вот зачем эти странные палочки?! И точно работает
| От: | rg45 |
| Дата: | 03.03.06 10:27 |
| Оценка: |
R>1. Либо «C://set.ds» либо «C:/set.ds» — двойной слэш — это лишний символ в строке, хотя большинством фунций «глотается» нормально.
Написал не то, что хотел, надо было так:
| От: | RevSegment |
| Дата: | 03.03.06 10:34 |
| Оценка: |
Здравствуйте, AlexDav, Вы писали:
AD>У меня было так
AD>
AD>Я открывал этот файл, при необходимости он создавался — и все было бы хорошо, но
AD>Я заменил на
AD>
AD>И все больше файл открываться не хочет! (и не создается) Я больше ничего не менял в программе — значит виноваты эти строки. Подскажите, плиз.
А так не пробовал?
«c:\\Folder One\\Folder Two\\file.ext»
| От: | AlexDav |
| Дата: | 03.03.06 10:46 |
| Оценка: |
Здравствуйте, LuciferMoscow, Вы писали:
LM>Попробуй путь взять в кавычки. У тебя есть пробел в пути к файлу
LM>
я попробовал такой путь «C:/Data/set.ds» работает — т.е. ты (можно на ты?) это пробелы, но как ты написал тоже не прокатывает?? Что Делать.
| От: | ekamaloff |
| Дата: | 03.03.06 10:50 |
| Оценка: |
Здравствуйте, AlexDav, Вы писали:
AD>я попробовал такой путь «C:/Data/set.ds» работает — т.е. ты (можно на ты?) это пробелы, но как ты написал тоже не прокатывает?? Что Делать.
Покажи где ты ее используешь и на каком варианте строки ты сейчас остановился.
| От: | AlexDav |
| Дата: | 03.03.06 11:07 |
| Оценка: |
Здравствуйте, ekamaloff, Вы писали:
E>Покажи где ты ее используешь и на каком варианте строки ты сейчас остановился.
Прошу прощения за MFC
| От: | AlexDav |
| Дата: | 03.03.06 13:35 |
| Оценка: |
Хотите верти — хотите нет, но
просто начала работать и все! Зуб даю кроме этой строчки в программе ничего не менял!
| От: | rg45 | |
| Дата: | 03.03.06 13:39 | |
| Оценка: | 4 (1) | |
Здравствуйте, AlexDav, Вы писали:
AD>Хотите верти — хотите нет, но
AD>
AD>просто начала работать и все! Зуб даю кроме этой строчки в программе ничего не менял!
Впервоначальном варианте у тебя все слэши были двойные. А петерь вместо них одинарные бэк-слэши (литерал «\\» автоматически преобразуется в одинарный бэк-слэш). Значит, какая то из функций не могла вынести присутствия лишних символов в строке.
| От: | i-maverick |
| Дата: | 03.03.06 13:48 |
| Оценка: |
Здравствуйте, AlexDav, Вы писали:
AD>Хотите верти — хотите нет, но
AD>
AD>просто начала работать и все! Зуб даю кроме этой строчки в программе ничего не менял!
Тебе ведь так и сказали — нужно либо одинарный прямой слэш, либо двойной обратный.
Ты бы хоть разобрался, зачем тут двойной слэш, чтоб больше не путаться.
| От: | AlexDav |
| Дата: | 03.03.06 13:54 |
| Оценка: |
Здравствуйте, i-maverick, Вы писали:
IM>Тебе ведь так и сказали — нужно либо одинарный прямой слэш, либо двойной обратный.
IM>Ты бы хоть разобрался, зачем тут двойной слэш, чтоб больше не путаться.
Ну ладно ругать то сразу — никто же не сказал что надо весь проект перекомпилить что бы подхватил эту дефайну
Пути к файлам
Казалось бы — что может быть проще, чем работа с файлами в C++. Но отдельные личности поражают своей находчивостью в поиске наихудшего подхода.
Не стоит делать так:
std::string filepath(«C:\\тест»);
std::ofstream file(filepath.c_str());
Если кратко, то использование не ASCII символов в строковых константах char может привести к печальным последствиям. Я уже обсуждал этот вопрос в посте о кодировках. В данном случае название файла напрямую зависит от кодировки исходника и если кто-то напишет подобное в utf-8, в windows-xp можно получить файл с запрещенными символами, с которым невозможно будет ничего сделать. Можно не использовать не ASCII. Но вы же не можете запретить это пользователю (потоку или БД из которого получен путь). Это же дискриминация по национальному признаку! Срочно исправляемся:
std::wstring filepath= L»C:\тест»
std::ofstream file(filepath.c_str());
Несведущие в стандарте пользователи Visual Studio могут успокоиться, пока нужда не заставит сменить компилятор (точнее STL). И тут начинается…
Дело в том, что текущий стандарт и не предполагает его наличия (не трогаем пока C++0x). Это в чистом виде энтузиазм мелкомягких.
Что же делать?
- Использовать стороннюю библиотеку для работы с путями (к примеру boost::filesystem)
- Использовать std::locale
- Придумывать свой
С третьим вариантом все ясно, с первым тоже ничего сложного:
- #include <boost/filesystem/fstream.hpp>
- #include <string>
- namespace fs = boost :: filesystem ;
- int main ( int argc, char * argv )
- <
- std :: wstring filepath ( L «C:\тест» ) ;
- fs :: ofstream ( filepath ) ;
- return 0 ;
- >
А вот по поводу второго у тех, кто не учил матчасть, могут возникнуть проблемы.
Пользуемся std::locale
Отступление.
Огорчу пользователей mingw: вам придется использовать стороннюю реализацию STL (к примеру stlport) из-за отсутствия в родной правильной поддержки локализации. А точнее, функция std::locale(«») всегда возвращает std::locale(«C»), что бы там у вас не стояло. Тот же stlport лишен подобного недостатка. О том как слепить связку mingw+stlport+boost я отписал тут.
Все что нам нужно сделать это следовать простым правилам — с не ASCII работаем в «расширенном» виде. То есть, читаем путь в std::wstring, используя соответствующим образом локализованный поток, а при использовании, сужаем по пользовательской локализации. Эта идея основана на том, что раз пользователь правильно видит символы своего языка в консоли, то его пользовательская локализация знает в какую кодировку надо сузить широкую строку, чтобы правильно интерпретировать путь. Итак, пример. Допустим у нас есть файл в кодировке cp866, содержащий путь. Нам необходимо создать файл по этому пути. Что мы делаем:
- #include <iostream>
- #include <string>
- #include <fstream>
- #include <locale>
- #include <memory>
- #include «facet/codecvt/codecvt_cp866.hpp»
- /**@brief Сужает широкую строку, используя локализацию loc
- @return Возвращает суженную строку или пустую суженную строку, в
- случае. если возникла ошибка*/
- std :: string narrow ( const std :: wstring & wstr, const std :: locale & loc )
- <
- const size_t sz = wstr. length ( ) ;
- if ( sz == 0 )
- return std :: string ( ) ;
- mbstate_t state = 0 ;
- char * cnext ;
- const wchar_t * wnext ;
- const wchar_t * wcstr = wstr. c_str ( ) ;
- char * buffer = new char [ sz + 1 ] ;
- std :: uninitialized_fill ( buffer, buffer + sz + 1 , 0 ) ;
- typedef std :: codecvt < wchar_t , char , mbstate_t > cvt ;
- cvt :: result res ;
- res = std :: use_facet < cvt > ( loc ) . out ( state, wcstr, wcstr + sz, wnext,
- buffer, buffer + sz, cnext ) ;
- std :: string result ( buffer ) ;
- if ( res == cvt :: error )
- return std :: string ( ) ;
- return result ;
- >
- /**@brief Расширяет строку, используя локализацию loc
- @return Возвращает расширенную строку или пустую расширенную строку, в
- случае, если возникла ошибка.*/
- std :: wstring widen ( const std :: string & str, const std :: locale & loc )
- <
- const size_t sz = str. length ( ) ;
- if ( sz == 0 )
- return std :: wstring ( ) ;
- mbstate_t state = 0 ;
- const char * cnext ;
- wchar_t * wnext ;
- const char * cstr = str. c_str ( ) ;
- wchar_t * buffer = new wchar_t [ sz + 1 ] ;
- std :: uninitialized_fill ( buffer, buffer + sz + 1 , 0 ) ;
- typedef std :: codecvt < wchar_t , char , mbstate_t > cvt ;
- cvt :: result res ;
- res = std :: use_facet < cvt > ( loc ) . in ( state, cstr, cstr + sz, cnext,
- buffer, buffer + sz, wnext ) ;
- std :: wstring result ( buffer ) ;
- delete [ ] buffer ;
- if ( res == cvt :: error )
- return std :: wstring ( ) ;
- return result ;
- >
- int main ( int argc, char * argv [ ] )
- <
- //Пусть имеется cp866 файл с путем
- std :: ofstream ofile ( «input.txt» , std :: ios :: binary ) ;
- if ( ! ofile )
- <
- std :: cerr << «Error open file» << std :: endl ;
- return 0 ;
- >
- std :: ostreambuf_iterator < char > writer ( ofile ) ;
- * ( writer ) = 0xe2 ; // т
- * ( ++ writer ) = 0xa5 ; // е
- * ( ++ writer ) = 0xe1 ; // с
- * ( ++ writer ) = 0xe2 ; // т
- ofile. close ( ) ;
- //Читаем путь
- std :: locale cp866 ( std :: locale ( ) , new codecvt_cp866 ) ;
- std :: wifstream ifile ( «input.txt» , std :: ios :: binary ) ;
- ifile. imbue ( cp866 ) ;
- std :: wstring wpath ;
- ifile >> wpath ;
- ifile >> wpath ;
- ifile. close ( ) ;
- //Создаем по этому пути файл
- std :: ofstream file ( narrow ( wpath, std :: locale ( «» ) ) . c_str ( ) ) ;
- file << «testing» ;
- file . close ( ) ;
- >
Фасеты можно взять на git-hub.
SUMMARY
Если вы используете путь из argv — можете смело с ним работать (пользователь знает что делает). Из «внешней среды» путь получайте с помощью правильно локализованного потока как широкую строку и сужайте ее с помощью пользовательской локализации.
С вопросами можно обращаться:
0. К стандарту
1. К книге Страуструпа (3-е специальное издание, приложение)
2. К документации по mingw.
3. К документации по boost.
4. К посту о фасетах и кодировках.
Всем прямых путей!
UPD: Ну и как правильно заметили Gorthauer87,Migun и naryl в комментариях, обратные слеши и платформо-специфичные пути тоже плохая идея.
Как прописать путь к txt-файлу?
Как указать путь к файлу который находится в той же директории что и сам проект, то есть чтобы можно было этот файл и проект перекинуть в другое место и он все таки находил этот файл не меняя пути к нему? FileStream f = new FileStream(@»C:\Users\User\Desktop\TaskOne\input.txt», FileMode.Open, FileAccess.Read);
Для это вам нужно оперировать двумя параметрами проекта Visual Studio:
- Working directory
- Output path
Возьмём для примера проект консольного приложения.

Параметр Working directory определяет, какая рабочая директория будет задана по умолчанию текущему процессу консольного приложения.
Если этот параметр пустой, то рабочей директория будет директория из которой запущен exe файл. А его место создание определяется параметром проекта Output path :

По умолчанию это поддиректорий текущего проекта bin\Debug.
Таким образом, в данном случае, чтобы обратиться к файлу input.txt находящемуся в директории проекта нужно обратиться на два директория выше, т.е. использовать «..» в пути файла:
Так как пути все указываются относительно директории проекта, то при переносе папки проекта изменять пути не надо будет.
Директорией проекта является директория, в которой лежит файл проекта .csproj .