latin/file.rs
1use std::convert::AsRef;
2use std::iter::IntoIterator;
3use std::path::Path;
4use std::io::{Result as IoResult, Error as IoError};
5use std::io::{Write, Read, BufRead, Lines, BufReader, BufWriter};
6use std::fs::{OpenOptions, File, remove_file};
7use std::fs::copy as fs_copy;
8
9#[cfg(windows)]
10const LINE_SEP: &'static [u8] = b"\r\n";
11
12#[cfg(not(windows))]
13const LINE_SEP: &'static [u8] = b"\n";
14
15/// Writes `content` into a file at `path`.
16///
17/// If the file at `path` does not exist, it will be created.
18/// Otherwise, the file will be completely overwritten.
19///
20/// ```rust,no_run
21/// // write a string
22/// latin::file::write("./foo.txt", "contents");
23/// // write bytes
24/// latin::file::write("./foo.txt", &[5u8, 10u8]);
25/// ```
26pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> IoResult<()> {
27 let file = try!(OpenOptions::new().write(true).create(true).truncate(true).open(path));
28 let mut file = BufWriter::new(file);
29 file.write_all(contents.as_ref())
30}
31
32/// Writes lines into a file at `path`.
33///
34/// If the file at `path` does not exist, it will be created.
35/// Otherwise, the file will be completely overwritten.
36///
37/// ```rust,no_run
38/// latin::file::write_lines("./foo.txt", vec!["line1", "line2"]);
39/// // works with iterators too
40/// latin::file::write_lines("./foo.txt", vec!["line1", "line2"].iter().map(|l| &l[0 .. 2]));
41/// ```
42pub fn write_lines<P: AsRef<Path>, I: IntoIterator<Item=B, IntoIter=A>, A: Iterator<Item=B>, B: AsRef<[u8]>>(path: P, lines: I) -> IoResult<()> {
43 let file = try!(OpenOptions::new().write(true).create(true).truncate(true).open(path));
44 let mut file = BufWriter::new(file);
45 for line in lines.into_iter() {
46 try!(file.write_all(line.as_ref()));
47 try!(file.write_all(LINE_SEP));
48 }
49 Ok(())
50}
51
52/// Appends some contents to the file at `path`.
53///
54/// If the file at `path` does not exist, it will be created.
55/// Otherwise, the file will be completely overwritten.
56///
57/// ```rust,no_run
58/// // append a string
59/// latin::file::append("./foo.txt", "appended content");
60/// // append bytes
61/// latin::file::append("./foo.txt", &[10u8, 5u8]);
62/// ```
63pub fn append<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> IoResult<()> {
64 let mut file = try!(OpenOptions::new().write(true).create(true).append(true).open(path));
65 file.write_all(contents.as_ref())
66}
67
68/// Appends some contents followed by a newline to the file at `path`.
69///
70/// The newline seperator will vary depending on operating system.
71/// Windows: "\r\n" All other: "\n"
72///
73/// If the file at `path` does not exist, it will be created.
74/// Otherwise, the file will be completely overwritten.
75///
76/// ```rust,no_run
77/// // append a line followed by a newline
78/// latin::file::append_line("./foo.txt", "appended line");
79/// // not sure why you'd want this, but this works too
80/// latin::file::append_line("./foo.txt", &[10u8, 5u8]);
81/// ```
82pub fn append_line<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> IoResult<()> {
83 let mut file = try!(OpenOptions::new().write(true).create(true).append(true).open(path));
84 try!(file.write_all(contents.as_ref()));
85 file.write_all(LINE_SEP)
86}
87
88/// Reads the file at `path` and returns the content as a Vec<u8>
89///
90/// If the file at `path` does not exist, an error is returned.
91///
92/// ```rust,no_run
93///# #![allow(unused)]
94/// let contents = latin::file::read("foo.txt");
95/// // or as a string
96/// let contents = latin::file::read("foo.txt").map(String::from_utf8);
97/// ```
98pub fn read<P: AsRef<Path>>(path: P) -> IoResult<Vec<u8>> {
99 let file = try!(OpenOptions::new().read(true).open(path));
100 let mut file = BufReader::new(file);
101 let mut out = vec![];
102 try!(file.read_to_end(&mut out));
103 Ok(out)
104}
105
106/// Reads the file at `path` and returns the content as a String
107///
108/// If the file at `path` does not exist or the file is not utf8,
109/// an error is returned.
110///
111/// ```rust,no_run
112///# #![allow(unused)]
113/// let contents = latin::file::read_string_utf8("foo.txt");
114/// ```
115pub fn read_string_utf8<P: AsRef<Path>>(path: P) -> IoResult<String> {
116 match read(path) {
117 Ok(bytes) => match String::from_utf8(bytes) {
118 Ok(s) => Ok(s),
119 Err(e) => Err(IoError::new(::std::io::ErrorKind::Other, e)),
120 },
121 Err(e) => Err(e)
122 }
123}
124
125/// Reads the file at `path` and returns the content as a String
126///
127/// If the file at `path` does not exist an error is returned.
128///
129/// Any non-utf8 characters are stripped from the result. Please
130/// see `std::String::from_utf8_lossy` for more info.
131///
132/// ```rust,no_run
133///# #![allow(unused)]
134/// let contents = latin::file::read_string_utf8_lossy("foo.txt");
135/// ```
136pub fn read_string_utf8_lossy<P: AsRef<Path>>(path: P) -> IoResult<String> {
137 match read(path) {
138 Ok(bytes) => Ok(String::from_utf8_lossy(&bytes[..]).into_owned()),
139 Err(e) => Err(e)
140 }
141}
142
143/// Reads all of the lines in a file at `path`.
144///
145/// Returns an iterator over the lines.
146///
147///
148/// ```rust,no_run
149/// for line in latin::file::read_lines("foo.txt").unwrap() {
150/// println!("{}", line.unwrap());
151/// }
152/// ```
153pub fn read_lines<P: AsRef<Path>>(path: P) -> IoResult<Lines<BufReader<File>>> {
154 let file = try!(OpenOptions::new().read(true).open(path));
155 let file = BufReader::new(file);
156 Ok(file.lines())
157}
158
159/// Returns true if `path` exists and is a file.
160///
161/// ```rust,no_run
162/// if latin::file::exists("foo.txt") {
163/// // do stuff
164/// }
165pub fn exists<P: AsRef<Path>>(path: P) -> bool {
166 let path = path.as_ref();
167 path.is_file() && path.exists()
168}
169
170/// Copies a file from `from` to `to`.
171///
172/// If the file at `to` does not exist, it will be created.
173/// Otherwise, the file will be completely overwritten.
174///
175/// ```rust,no_run
176/// latin::file::copy("foo.txt", "bar.txt");
177/// ```
178pub fn copy<Fp: AsRef<Path>, Tp: AsRef<Path>>(from: Fp, to: Tp) -> IoResult<()> {
179 fs_copy(from, to).map(|_| ())
180}
181
182/// Removes the file at `path`.
183///
184/// An error is removed if `path` is not a file, or if
185/// the file could not be removed for filesystem reasons.
186///
187/// ```rust,no_run
188/// latin::file::remove("./foo.txt");
189/// ```
190pub fn remove<P: AsRef<Path>>(path: P) -> IoResult<()> {
191 remove_file(path)
192}
193
194/// Checks to see if the file at `path` has the file extension `ext`.
195pub fn has_extension<P: AsRef<Path>, S: AsRef<str>>(path: P, ext: S) -> bool {
196 path.as_ref().extension()
197 .and_then(|ext| ext.to_str())
198 .map(|provided_ext| provided_ext == ext.as_ref())
199 .unwrap_or(false)
200}