Path
Path用於表示目錄名,也可以是一個文件。路徑以根目錄開始的爲據對路徑,否則就是相對路徑。例如假設使用Linux系統:
//絕對路徑:/home/temp
Path absolute = Paths.get("/home", "temp");
Path absolute1 = Paths.get("/home/temp");
//相對路徑:document/work/test.txt
Path relative = Paths.get("document", "work", "test.txt");
Path relative1 = Paths.get("document/work/test.txt");
Paths.get方法接收一個或多個字符串,並使用系統默認的路徑分隔符(Linux爲/,Windows爲\)。Path類提供了一系列方法構建目錄結構。
-
resolve(Path other)
,resolve(String other)
:基於this與other構建新的Path,如果other爲絕對路徑,則返回other,否則返回this+other的拼接的路徑:
//path:/home
Path path = Paths.get("/home");
//other:/home/work
Path other = path.resolve("work");
//other1:/home/document
Path other1 = path.resolve("/home/document");
//other2:/home/work
Path other2 = path.resolve(Paths.get("work"));
-
resolveSibling(Path other)
,resolveSibling(String other)
:基於this構建相對同級路徑。如果other是絕對路徑,返回other,否則返回this上級路徑+other。 -
relativize(Path other)
:返回other相對於this的相對路徑 - toAbsolutePath():轉換爲絕對路徑。
//path:/home
Path path = Paths.get("/home/work");
//other:/home/document
Path other = path.resolveSibling("document");
//other1:/user/document
Path other1 = path.resolveSibling("/user/document");
//other2:/home/document/user
Path other2 = path.resolveSibling(Paths.get("document/user"));
//relative: ../document/user
Path relative = path.relativize(other2);
//absolute:/Volumns/ServerDevelop/home/work,其中/Volumns/ServerDevelop爲工作目錄
Path absolute = path.toAbsolutePath();
- getParent():返回上級路徑,若沒有上級路徑則返回null。
- getFileName():獲取路徑的最好一個元素,有可能是目錄或文件。
- getRoot():獲取根路徑。
- toFile():從該路徑創建一個File對象,注意,不是創建一個文件。
Files
Files類使得普通文件操作變得快捷。通過Path提供的文件路徑,可以直接從文件讀寫行、字節、字符串內容,也可以使用流的方式處理文件讀寫。
- Files.readAllLines(Path path):從path中讀取全部行,返回List<String>;
- Files.readAllLines(Path path):從path中讀取全部字節,返回byte數組;
- Files.newInputStream(Path path):以path構建輸入流;
- Files.newOutputStream(Path path, OpenOption options):以path構建輸出流,其中輸出的方式通過options配置。
- Files.createDirectory(Path path):創建path目錄,注意指揮創建當級目錄,若創建失敗(如目錄已存在或上級路徑不存在)則會拋出異常。
- Files.createDirectories(Path path):如果路徑中間目錄不存在這會將中間路徑也創建。
- Files.exists(Path path):判斷路徑是否存在。
- Files.copy(Path fromPath, Path toPath, CopyOption options):將fromPath複製到toPath且保留源文件,根據options決定toPath的行爲是覆蓋,複製文件屬性還是原子性移動文件(ATOMIC_MOVE)。
- Files.move(Path fromPath, Path toPath, CopyOption options):將fromPath複製到toPath,不保留源文件,根據options決定toPath的行爲是覆蓋,複製文件屬性還是原子性移動文件(ATOMIC_MOVE)。
- Files.delete(Path path):刪除path文件目錄或文件。文件不存在的情況會拋異常。
- Files.deleteIfExists(Path path):刪除path文件目錄或文件,文件不存在不做任何操作。
public class FilesBasic {
public static void main(String[] args) throws IOException {
Path path = Paths.get("./DesignPattern/src/practise/lios/demo/alice.txt");
//按行讀取全部內容
List<String> lines = Files.readAllLines(path);
lines.stream().limit(10).forEach(System.out::println);
//按字節讀取全部內容
byte[] bytes = Files.readAllBytes(path);
String bytesToString = new String(bytes, 0 , 100);
System.out.println("bytes:\n" + bytesToString);
//通過InputStream讀取內容
InputStream inputStream = Files.newInputStream(path);
Scanner inputScanner = new Scanner(inputStream, StandardCharsets.UTF_8);
final int maxLine = 10;
int line = 0;
System.out.println("Input Stream:");
while(inputScanner.hasNextLine() && line < maxLine) {
String contents = inputScanner.nextLine();
line ++;
System.out.println(contents);
}
//通過OutputStream寫內容到文件
Path outputDirectory = Paths.get("output");
//目錄不存在的話創建目錄
if (! Files.exists(outputDirectory)) {
Files.createDirectory(outputDirectory);
}
//將輸出文件放入到新加的目錄下
Path outPath = outputDirectory.resolve("output.txt");
boolean fileExists = Files.exists(outPath);
OutputStream outputStream;
if (fileExists) {
outputStream = Files.newOutputStream(outPath, StandardOpenOption.APPEND);
} else {
outputStream = Files.newOutputStream(outPath, StandardOpenOption.CREATE);
}
outputStream.write(bytes, 0, 100);
//文件移動、複製及刪除
Path parentPath = outputDirectory.toAbsolutePath().getParent();
if (parentPath != null) {
Path destinationFilePath = parentPath.resolve("output.txt");
//如果文件存在則替換掉
Path copyPath = Files.copy(outPath, destinationFilePath, StandardCopyOption.REPLACE_EXISTING);
Path movedFilePath = parentPath.resolve("output1.txt");
Path movedPath = Files.move(outPath, movedFilePath, StandardCopyOption.REPLACE_EXISTING);
Files.delete(outputDirectory);
}
}
}
Files獲取文件的基本信息
可以通過Files的方法獲取文件的如下屬性:
- 是否存在、是否是常規文件、是否是鏈接、是否是目錄;
- 是否可讀,是否可寫,是否可執行;
- 文件大小
- 文件的創建、最近修改和最近訪問時間
public static void showFileInfo(Path path) throws IOException {
boolean fileExists = Files.exists(path);
System.out.println("File exists: " + fileExists);
if (fileExists) {
boolean isHidden = Files.isHidden(path);
System.out.println("File is hidden: " + isHidden);
boolean isReadable = Files.isReadable(path);
System.out.println("File is readable: " + isReadable);
boolean isWritable = Files.isWritable(path);
System.out.println("File is writable: " + isWritable);
boolean isExecutable = Files.isExecutable(path);
System.out.println("File is executable: " + isExecutable);
boolean isDirectory = Files.isDirectory(path);
System.out.println("File is directory: " + isDirectory);
boolean isSymbolicLink = Files.isSymbolicLink(path);
System.out.println("File is symbolic link: " + isSymbolicLink);
boolean isRegularFile = Files.isRegularFile(path);
if (isRegularFile) {
long fileSize = Files.size(path);
System.out.printf("File size: %.1fkB \n",(float)fileSize / 1024);
//BasicFileAttributes包含上述的全部屬性封裝
BasicFileAttributes attributes = Files.readAttributes(path, BasicFileAttributes.class);
System.out.println("File size: " + attributes.size() + "bytes");
System.out.println("File created at: " + attributes.creationTime());
System.out.println("File last modified at: " + attributes.lastModifiedTime());
System.out.println("File last accessed at: " + attributes.lastAccessTime());
}
}
}
目錄遍歷
Files.list(Path path)方法將遍歷path下的目錄(不包含下下級目錄),返回Stream<Path>對象;Files.walk(Path path)返回path下的全部目錄(包含全部子孫目錄),返回Stream<Path>對象。
try (Stream<Path> entries = Files.list(path)) {
entries.forEach(p -> {
if (Files.isDirectory(p)) {
System.out.println("Directory: " + p);
} else {
System.out.println("File: " + p);
}
});
}
try (Stream<Path> entries = Files.walk(path)) {
entries.forEach(p -> {
if (Files.isDirectory(p)) {
System.out.println("Directory: " + p);
} else {
System.out.println("File: " + p);
}
});
}
文件訪問效率
可以通過使用BufferedInputStream或FileChannel的map方法將文件映射到內存中,從而提高訪問效率。其中FileChannel的map方法支持隨機訪問文件內容。
public class MemoryMapFile {
public static long checkSumWithInputStream(Path filename) throws IOException {
try (InputStream inputStream = Files.newInputStream(filename)) {
CRC32 crc32 = new CRC32();
int c;
while((c = inputStream.read()) != -1) {
crc32.update(c);
}
return crc32.getValue();
}
}
public static long checkSumWithBufferedInputStream(Path filename) throws IOException {
try (BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(filename))) {
CRC32 crc32 = new CRC32();
int c;
while((c = inputStream.read()) != -1) {
crc32.update(c);
}
return crc32.getValue();
}
}
public static long checkSumWithRandomAccessFile(Path filename) throws IOException {
try (RandomAccessFile file = new RandomAccessFile(filename.toFile(), "r")) {
long length = file.length();
CRC32 crc32 = new CRC32();
for (long i = 0; i < length; ++i) {
file.seek(i);
int c = file.readByte();
crc32.update(c);
}
return crc32.getValue();
}
}
public static long checkSumWithMappedFile(Path filename) throws IOException {
try (FileChannel fileChannel = FileChannel.open(filename)) {
CRC32 crc32 = new CRC32();
int length = (int)fileChannel.size();
MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, length);
for (int i = 0; i < length; ++i) {
int c = buffer.get(i);
crc32.update(c);
}
return crc32.getValue();
}
}
public static void main(String[] args) throws IOException {
Path path = Paths.get("./DesignPattern/src/practise/lios/demo/alice.txt");
long start = System.currentTimeMillis();
long crcValue = checkSumWithInputStream(path);
long end = System.currentTimeMillis();
System.out.println("CRC value: " + Long.toHexString(crcValue));
System.out.println("InputStream Running time: " + (end - start) + " milliseconds");
start = System.currentTimeMillis();
crcValue = checkSumWithBufferedInputStream(path);
end = System.currentTimeMillis();
System.out.println("CRC value: " + Long.toHexString(crcValue));
System.out.println("BufferedInputStream Running time: " + (end - start) + " milliseconds");
start = System.currentTimeMillis();
crcValue = checkSumWithRandomAccessFile(path);
end = System.currentTimeMillis();
System.out.println("CRC value: " + Long.toHexString(crcValue));
System.out.println("RandomAccessFile Running time: " + (end - start) + " milliseconds");
start = System.currentTimeMillis();
crcValue = checkSumWithMappedFile(path);
end = System.currentTimeMillis();
System.out.println("CRC value: " + Long.toHexString(crcValue));
System.out.println("MappedFile Running time: " + (end - start) + " milliseconds");
}
}
運行結果如下:
CRC value: 11891d02
InputStream Running time: 185 milliseconds
CRC value: 11891d02
BufferedInputStream Running time: 9 milliseconds
CRC value: 11891d02
RandomAccessFile Running time: 221 milliseconds
CRC value: 11891d02
MappedFile Running time: 5 milliseconds
可以看到文件訪問的效率爲:MappedFile > BufferInputStream > InputStream > RandomAccessFile