Newer
Older
dub_jkp / source / vibe / core / file.d
@Sönke Ludwig Sönke Ludwig on 22 Feb 2013 6 KB Fixed downloading of files.
  1. /**
  2. File handling.
  3.  
  4. Copyright: © 2012 RejectedSoftware e.K.
  5. License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file.
  6. Authors: Sönke Ludwig
  7. */
  8. module vibe.core.file;
  9.  
  10. public import vibe.inet.url;
  11. public import std.stdio;
  12.  
  13. import vibe.core.log;
  14.  
  15. import std.conv;
  16. import std.c.stdio;
  17. import std.datetime;
  18. import std.exception;
  19. import std.file;
  20. import std.path;
  21. import std.string;
  22. import std.utf;
  23.  
  24.  
  25. version(Posix){
  26. private extern(C) int mkstemps(char* templ, int suffixlen);
  27. }
  28.  
  29.  
  30. /* Add output range support to File
  31. */
  32. struct RangeFile {
  33. File file;
  34. alias file this;
  35.  
  36. void put(in char[] str) { file.write(str); }
  37. void put(char ch) { file.write(cast(ubyte)ch); }
  38. void put(dchar ch) { char[4] chars; put(chars[0 .. encode(chars, ch)]); }
  39. ubyte[] readAll()
  40. {
  41. file.seek(0, SEEK_END);
  42. auto sz = file.tell();
  43. enforce(sz <= size_t.max, "File is too big to read to memory.");
  44. file.seek(0, SEEK_SET);
  45. auto ret = new ubyte[cast(size_t)sz];
  46. return file.rawRead(ret);
  47. }
  48. }
  49.  
  50.  
  51. /**
  52. Opens a file stream with the specified mode.
  53. */
  54. RangeFile openFile(Path path, FileMode mode = FileMode.Read)
  55. {
  56. string strmode;
  57. final switch(mode){
  58. case FileMode.Read: strmode = "rb"; break;
  59. case FileMode.ReadWrite: strmode = "rb+"; break;
  60. case FileMode.CreateTrunc: strmode = "wb+"; break;
  61. case FileMode.Append: strmode = "ab"; break;
  62. }
  63. auto ret = File(path.toNativeString(), strmode);
  64. assert(ret.isOpen());
  65. return RangeFile(ret);
  66. }
  67. /// ditto
  68. RangeFile openFile(string path, FileMode mode = FileMode.Read)
  69. {
  70. return openFile(Path(path), mode);
  71. }
  72.  
  73. /**
  74. Creates and opens a temporary file for writing.
  75. */
  76. RangeFile createTempFile(string suffix = null)
  77. {
  78. version(Windows){
  79. char[L_tmpnam] tmp;
  80. tmpnam(tmp.ptr);
  81. auto tmpname = to!string(tmp.ptr);
  82. if( tmpname.startsWith("\\") ) tmpname = tmpname[1 .. $];
  83. tmpname ~= suffix;
  84. logDebug("tmp %s", tmpname);
  85. return openFile(tmpname, FileMode.CreateTrunc);
  86. } else {
  87. enum pattern ="/tmp/vtmp.XXXXXX";
  88. scope templ = new char[pattern.length+suffix.length+1];
  89. templ[0 .. pattern.length] = pattern;
  90. templ[pattern.length .. $-1] = suffix;
  91. templ[$-1] = '\0';
  92. assert(suffix.length <= int.max);
  93. auto fd = mkstemps(templ.ptr, cast(int)suffix.length);
  94. enforce(fd >= 0, "Failed to create temporary file.");
  95. return File.wrapFile(fdopen(fd));
  96. }
  97. }
  98.  
  99. /**
  100. Moves or renames a file.
  101. */
  102. void moveFile(Path from, Path to)
  103. {
  104. moveFile(from.toNativeString(), to.toNativeString());
  105. }
  106. /// ditto
  107. void moveFile(string from, string to)
  108. {
  109. std.file.rename(from, to);
  110. }
  111.  
  112. /**
  113. Copies a file.
  114.  
  115. Note that attributes and time stamps are currently not retained.
  116.  
  117. Params:
  118. from = Path of the source file
  119. to = Path for the destination file
  120. overwrite = If true, any file existing at the destination path will be
  121. overwritten. If this is false, an excpetion will be thrown should
  122. a file already exist at the destination path.
  123.  
  124. Throws:
  125. An Exception if the copy operation fails for some reason.
  126. */
  127. void copyFile(Path from, Path to, bool overwrite = false)
  128. {
  129. {
  130. auto src = openFile(from, FileMode.Read);
  131. scope(exit) src.close();
  132. enforce(overwrite || !existsFile(to), "Destination file already exists.");
  133. auto dst = openFile(to, FileMode.CreateTrunc);
  134. scope(exit) dst.close();
  135. dst.write(src);
  136. }
  137.  
  138. // TODO: retain attributes and time stamps
  139. }
  140. /// ditto
  141. void copyFile(string from, string to)
  142. {
  143. copyFile(Path(from), Path(to));
  144. }
  145.  
  146. /**
  147. Removes a file
  148. */
  149. void removeFile(Path path)
  150. {
  151. removeFile(path.toNativeString());
  152. }
  153. /// ditto
  154. void removeFile(string path) {
  155. std.file.remove(path);
  156. }
  157.  
  158. /**
  159. Checks if a file exists
  160. */
  161. bool existsFile(Path path) {
  162. return existsFile(path.toNativeString());
  163. }
  164. /// ditto
  165. bool existsFile(string path)
  166. {
  167. return std.file.exists(path);
  168. }
  169.  
  170. /** Stores information about the specified file/directory into 'info'
  171.  
  172. Returns false if the file does not exist.
  173. */
  174. FileInfo getFileInfo(Path path)
  175. {
  176. auto ent = std.file.dirEntry(path.toNativeString());
  177. return makeFileInfo(ent);
  178. }
  179. /// ditto
  180. FileInfo getFileInfo(string path)
  181. {
  182. return getFileInfo(Path(path));
  183. }
  184.  
  185. /**
  186. Creates a new directory.
  187. */
  188. void createDirectory(Path path)
  189. {
  190. mkdir(path.toNativeString());
  191. }
  192. /// ditto
  193. void createDirectory(string path)
  194. {
  195. createDirectory(Path(path));
  196. }
  197.  
  198. /**
  199. Enumerates all files in the specified directory.
  200. */
  201. void listDirectory(Path path, scope bool delegate(FileInfo info) del)
  202. {
  203. foreach( DirEntry ent; dirEntries(path.toNativeString(), SpanMode.shallow) )
  204. if( !del(makeFileInfo(ent)) )
  205. break;
  206. }
  207. /// ditto
  208. void listDirectory(string path, scope bool delegate(FileInfo info) del)
  209. {
  210. listDirectory(Path(path), del);
  211. }
  212. /// ditto
  213. int delegate(scope int delegate(ref FileInfo)) iterateDirectory(Path path)
  214. {
  215. int iterator(scope int delegate(ref FileInfo) del){
  216. int ret = 0;
  217. listDirectory(path, (fi){
  218. ret = del(fi);
  219. return ret == 0;
  220. });
  221. return ret;
  222. }
  223. return &iterator;
  224. }
  225. /// ditto
  226. int delegate(scope int delegate(ref FileInfo)) iterateDirectory(string path)
  227. {
  228. return iterateDirectory(Path(path));
  229. }
  230.  
  231.  
  232. /**
  233. Returns the current working directory.
  234. */
  235. Path getWorkingDirectory()
  236. {
  237. return Path(std.file.getcwd());
  238. }
  239.  
  240.  
  241. /** Contains general information about a file.
  242. */
  243. struct FileInfo {
  244. /// Name of the file (not including the path)
  245. string name;
  246.  
  247. /// Size of the file (zero for directories)
  248. ulong size;
  249.  
  250. /// Time of the last modification
  251. SysTime timeModified;
  252.  
  253. /// Time of creation (not available on all operating systems/file systems)
  254. SysTime timeCreated;
  255.  
  256. /// True if this is a symlink to an actual file
  257. bool isSymlink;
  258.  
  259. /// True if this is a directory or a symlink pointing to a directory
  260. bool isDirectory;
  261. }
  262.  
  263. /**
  264. Specifies how a file is manipulated on disk.
  265. */
  266. enum FileMode {
  267. /// The file is opened read-only.
  268. Read,
  269. /// The file is opened for read-write random access.
  270. ReadWrite,
  271. /// The file is truncated if it exists and created otherwise and the opened for read-write access.
  272. CreateTrunc,
  273. /// The file is opened for appending data to it and created if it does not exist.
  274. Append
  275. }
  276.  
  277. /**
  278. Accesses the contents of a file as a stream.
  279. */
  280.  
  281. private FileInfo makeFileInfo(DirEntry ent)
  282. {
  283. FileInfo ret;
  284. ret.name = baseName(ent.name);
  285. if( ret.name.length == 0 ) ret.name = ent.name;
  286. assert(ret.name.length > 0);
  287. ret.size = ent.size;
  288. ret.timeModified = ent.timeLastModified;
  289. version(Windows) ret.timeCreated = ent.timeCreated;
  290. else ret.timeCreated = ent.timeLastModified;
  291. ret.isSymlink = ent.isSymlink;
  292. ret.isDirectory = ent.isDir;
  293. return ret;
  294. }
  295.