Как получить полный путь к файлу c
Перейти к содержимому

Как получить полный путь к файлу c

Пути к файлам

Казалось бы — что может быть проще, чем работа с файлами в 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
  • Придумывать свой

С третьим вариантом все ясно, с первым тоже ничего сложного:

  1. #include <boost/filesystem/fstream.hpp>
  2. #include <string>
  3. namespace fs = boost :: filesystem ;
  4. int main ( int argc, char * argv )
  5. <
  6. std :: wstring filepath ( L «C:\тест» ) ;
  7. fs :: ofstream ( filepath ) ;
  8. return 0 ;
  9. >

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

Пользуемся std::locale

Отступление.
Огорчу пользователей mingw: вам придется использовать стороннюю реализацию STL (к примеру stlport) из-за отсутствия в родной правильной поддержки локализации. А точнее, функция std::locale(«») всегда возвращает std::locale(«C»), что бы там у вас не стояло. Тот же stlport лишен подобного недостатка. О том как слепить связку mingw+stlport+boost я отписал тут.

Все что нам нужно сделать это следовать простым правилам — с не ASCII работаем в «расширенном» виде. То есть, читаем путь в std::wstring, используя соответствующим образом локализованный поток, а при использовании, сужаем по пользовательской локализации. Эта идея основана на том, что раз пользователь правильно видит символы своего языка в консоли, то его пользовательская локализация знает в какую кодировку надо сузить широкую строку, чтобы правильно интерпретировать путь. Итак, пример. Допустим у нас есть файл в кодировке cp866, содержащий путь. Нам необходимо создать файл по этому пути. Что мы делаем:

  1. #include <iostream>
  2. #include <string>
  3. #include <fstream>
  4. #include <locale>
  5. #include <memory>
  6. #include «facet/codecvt/codecvt_cp866.hpp»
  7. /**@brief Сужает широкую строку, используя локализацию loc
  8. @return Возвращает суженную строку или пустую суженную строку, в
  9. случае. если возникла ошибка*/
  10. std :: string narrow ( const std :: wstring & wstr, const std :: locale & loc )
  11. <
  12. const size_t sz = wstr. length ( ) ;
  13. if ( sz == 0 )
  14. return std :: string ( ) ;
  15. mbstate_t state = 0 ;
  16. char * cnext ;
  17. const wchar_t * wnext ;
  18. const wchar_t * wcstr = wstr. c_str ( ) ;
  19. char * buffer = new char [ sz + 1 ] ;
  20. std :: uninitialized_fill ( buffer, buffer + sz + 1 , 0 ) ;
  21. typedef std :: codecvt < wchar_t , char , mbstate_t > cvt ;
  22. cvt :: result res ;
  23. res = std :: use_facet < cvt > ( loc ) . out ( state, wcstr, wcstr + sz, wnext,
  24. buffer, buffer + sz, cnext ) ;
  25. std :: string result ( buffer ) ;
  26. if ( res == cvt :: error )
  27. return std :: string ( ) ;
  28. return result ;
  29. >
  30. /**@brief Расширяет строку, используя локализацию loc
  31. @return Возвращает расширенную строку или пустую расширенную строку, в
  32. случае, если возникла ошибка.*/
  33. std :: wstring widen ( const std :: string & str, const std :: locale & loc )
  34. <
  35. const size_t sz = str. length ( ) ;
  36. if ( sz == 0 )
  37. return std :: wstring ( ) ;
  38. mbstate_t state = 0 ;
  39. const char * cnext ;
  40. wchar_t * wnext ;
  41. const char * cstr = str. c_str ( ) ;
  42. wchar_t * buffer = new wchar_t [ sz + 1 ] ;
  43. std :: uninitialized_fill ( buffer, buffer + sz + 1 , 0 ) ;
  44. typedef std :: codecvt < wchar_t , char , mbstate_t > cvt ;
  45. cvt :: result res ;
  46. res = std :: use_facet < cvt > ( loc ) . in ( state, cstr, cstr + sz, cnext,
  47. buffer, buffer + sz, wnext ) ;
  48. std :: wstring result ( buffer ) ;
  49. delete [ ] buffer ;
  50. if ( res == cvt :: error )
  51. return std :: wstring ( ) ;
  52. return result ;
  53. >
  54. int main ( int argc, char * argv [ ] )
  55. <
  56. //Пусть имеется cp866 файл с путем
  57. std :: ofstream ofile ( «input.txt» , std :: ios :: binary ) ;
  58. if ( ! ofile )
  59. <
  60. std :: cerr << «Error open file» << std :: endl ;
  61. return 0 ;
  62. >
  63. std :: ostreambuf_iterator < char > writer ( ofile ) ;
  64. * ( writer ) = 0xe2 ; // т
  65. * ( ++ writer ) = 0xa5 ; // е
  66. * ( ++ writer ) = 0xe1 ; // с
  67. * ( ++ writer ) = 0xe2 ; // т
  68. ofile. close ( ) ;
  69. //Читаем путь
  70. std :: locale cp866 ( std :: locale ( ) , new codecvt_cp866 ) ;
  71. std :: wifstream ifile ( «input.txt» , std :: ios :: binary ) ;
  72. ifile. imbue ( cp866 ) ;
  73. std :: wstring wpath ;
  74. ifile >> wpath ;
  75. ifile >> wpath ;
  76. ifile. close ( ) ;
  77. //Создаем по этому пути файл
  78. std :: ofstream file ( narrow ( wpath, std :: locale ( «» ) ) . c_str ( ) ) ;
  79. file << «testing» ;
  80. file . close ( ) ;
  81. >

Фасеты можно взять на git-hub.

SUMMARY

Если вы используете путь из argv — можете смело с ним работать (пользователь знает что делает). Из «внешней среды» путь получайте с помощью правильно локализованного потока как широкую строку и сужайте ее с помощью пользовательской локализации.

С вопросами можно обращаться:
0. К стандарту
1. К книге Страуструпа (3-е специальное издание, приложение)
2. К документации по mingw.
3. К документации по boost.
4. К посту о фасетах и кодировках.

Всем прямых путей!

UPD: Ну и как правильно заметили Gorthauer87,Migun и naryl в комментариях, обратные слеши и платформо-специфичные пути тоже плохая идея.

Получение полного пути к файлу

По идее, после компиляции в path должен храниться полный путь к файлу, но вместо C:\Program Files (x86)\IIS Express\имя_файла , даже если файл хранится на рабочем столе, то путь будет C:\Program Files (x86)\IIS Express\ .

Что я сделал не так?

user avatar

user avatar

FileName — это имя файла на клиентской машине. Оно вообще ничего не значит на серверной стороне.

Судя по комментам, имя файла вам нужно чтобы получить полный путь к нему, прочитать его содержимое и записать в базу данных. На самом деле файл к этому моменту уже был открыт, прочитан с диска браузером, отправлен из браузера на сервер. И для записи в базу данных вам не нужно его открывать и читать.

Вся схема работает примерно так:

  1. Пользователь выбирает файл в диалоге браузера
  2. Браузер целиком читает файл и отправляет его содержимое и имя на сервер.
  3. Сервер получает и содержимое и имя от браузера, и отдает их вам в виде свойств FileUpload .

Имя в этом случае — простро строчка, а не реальное имя файла на сервере. А содержимое — просто массив байт.

Вам достаточно взять готовое содержимое файла из FileUpload1.FileBytes и записать его в базу. Пытаться открыть файл по имени бессмысленно — потому что имя файла — это просто строчка, которая вообще ничего не значит на стороне сервера.

Path. Get Full Path Метод

Некоторые сведения относятся к предварительной версии продукта, в которую до выпуска могут быть внесены существенные изменения. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.

Перегрузки

Возвращает для указанной строки пути абсолютный путь.

Возвращает абсолютный путь из относительного пути и полного базового пути.

GetFullPath(String)

Возвращает для указанной строки пути абсолютный путь.

Параметры

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

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

Полное расположение path , например "C:\MyFile.txt".

Исключения

path — строка нулевой длины, содержит только пробелы в системах Windows или содержит один или несколько недопустимых символов, определенных в GetInvalidPathChars().

Система не может извлечь абсолютный путь.

У вызывающего объекта отсутствуют необходимые разрешения.

path имеет значение null .

path содержит двоеточие (:), которое не является частью идентификатора тома (например, "c:\").

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

Примеры

В следующем примере демонстрируется GetFullPath метод на платформе настольных компьютеров на основе Windows.

Комментарии

Абсолютный путь включает все сведения, необходимые для поиска файла или каталога в системе.

Файл или каталог, указанный параметром path , не обязательно должен существовать. Например, если c:\tempnewdir\ является текущим каталогом, вызов GetFullPath имени файла, например test.txt возвращает c:\tempnewdir\\test.txt. Файл не должен существовать.

Если path это относительный путь, эта перегрузка возвращает полный путь, который может быть основан на текущем диске и текущем каталоге. Текущий диск и текущий каталог могут изменяться в любое время при выполнении приложения. В результате путь, возвращаемый этой перегрузкой, не может быть определен заранее. Чтобы вернуть детерминированный путь, вызовите перегрузку GetFullPath(String, String) . Вы также можете вызвать метод, IsPathFullyQualified чтобы определить, является ли путь полным или относительным, и, следовательно, требуется ли вызов GetFullPath .

Однако если path он существует, вызывающий объект должен иметь разрешение на получение сведений о пути. path Обратите внимание, что в отличие от большинства членов Path класса этот метод обращается к файловой системе.

Этот метод использует текущий каталог и сведения о текущем томе для полного определения path . Если указать только имя path файла, GetFullPath возвращает полный путь к текущему каталогу.

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

Если путь не содержит значимых символов, он является недопустимым, если он не содержит один или несколько символов ". затем он будет проанализирован как "." или "..".

.NET Core 1.1 и более поздних версий и платформа .NET Framework 4.6.2 и более поздних версий также поддерживают пути, включающие имена устройств, например "\\?\ C:\".

Дополнительные сведения о форматах пути к файлам в Windows см. в форматах пути к файлам в системах Windows. Список распространенных задач ввода-вывода см. в разделе "Общие задачи ввода-вывода".

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *