File类
File类是java.io包下代表与平台无关的文件和目录,换句话说,如果希望在程序中操作文件和目录,都可以通过File类来完成。值得指出的是,不管是文件还是目录都是通过file来操作的,file能新建、删除、重命名文件和目录,File不能访问文件内容本身。如果要访问文件内容本身,则需要使用输入输出流。
常用的方法
@Test
public void fileTest() throws IOException {
// 以当前路径来创建一个File对象
File file = new File(".");
// 输出文件名 .
System.out.println(file.getName());
// 获取相对路径的父路径 null
System.out.println(file.getParent());
// 获取绝对路径 C:\workspace\java-test\test-jdk8\.
System.out.println(file.getAbsoluteFile());
// 获取上一级路径 C:\workspace\java-test\test-jdk8
System.out.println(file.getAbsoluteFile().getParent());
// 在当前路径下创建一个临时文件
File tempFile = File.createTempFile("aaa", ".txt", file);
// 当JVM退出时删除该文件按
tempFile.deleteOnExit();
// 以系统当前时间作为新文件名来创建新文件
File newFile = new File(String.valueOf(System.currentTimeMillis()));
// 检查文件是否存在 newFile是否存在:false
System.out.println("newFile是否存在:" + newFile.exists());
// 以指定newFile对象来创建一个文件 true
System.out.println(newFile.createNewFile());
//以newFile对象来创建一个目录,因为neeFile已经存在,所以下面方法返回false,即无法创建目录
System.out.println(newFile.mkdir());
/*
使用list()方法列出当前路径下的所有文件和路径
1600865736147
aaa8104162131771530421.txt
HELP.md
pom.xml
src
target
test-jdk8.iml
test-stream.iml
*/
String[] fileList = file.list();
if(null != fileList)
Arrays.stream(fileList).forEach(System.out::println);
/*
其中File类的list()方法可以接收一个FilenameFilter参数,通过该参数可以只列出符合条件的文件。
HELP.md
src
target
*/
String[] fileNames = file.list(((dir, name) -> name.endsWith(".md") || new File(name).isDirectory()));
if(null != fileNames)
Arrays.stream(fileNames).forEach(System.out::println);
// 静态方法列出所有的磁盘根路径 C:\
File[] roots = File.listRoots();
Arrays.stream(roots).forEach(System.out::println);
}
IO流
java中常见的几种流
根据流的流向,可以分为输入流和输出流,这个地方划分输入输出是从程序运行所在内存的角度来考虑的。输入流,只能从中读取数据,基类主要是InputStream和Reader;输出流,只能向其写入数据,基类主要是OutStream和Write。
根据流操作的数据单元,可以分为字节流与字符流,字节流的数据单元是8位的字节,字符流操作的数据单元是16位的字符。字节流主要是InputStream和OutStream作为基类,而字符流主要是Reader和Writer作为基类。
字节流与字符流的用法几乎完全一样,就一起测试了。
/**
* 测试字节输入流
* @throws IOException
*/
@Test
public void fileInputStreamTest() throws IOException {
// 创建字节输入流
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\82409\\Desktop\\error.log");
/*
创建一个长度为1024的字节数组来读取文件
这里创建较小长度的自己数组,程序运行时输出中文注释时就可能出现乱码,这是由于文件保存时采用的时GBK编码,每个中文字符占两个字节,如果read()方法读取时
只读到半个中文字符就会导致乱码
*/
byte[] buf = new byte[1024];
// 用于保存实际读取的字节数
int hasRaed = 0;
while ((hasRaed = fileInputStream.read(buf)) > 0) {
System.out.println(new String(buf, 0, hasRaed));
}
fileInputStream.close();
}
/**
* 测试字符输入流
* @throws IOException
*/
@Test
public void fileReaderTest() throws IOException {
// 创建字符输入流
FileReader fileReader = new FileReader("C:\\Users\\82409\\Desktop\\error.log");
// 创建一个长度为32的字符数组来读取文件
char[] buf = new char[32];
//用于保存实际读取的字符数
int hasRead = 0;
while ((hasRead = fileReader.read(buf)) > 0) {
System.out.println("FileReader输出:" + new String(buf, 0, hasRead));
}
fileReader.close();
// BufferReader有一个readline()方法,可以很方便地一次读取一行内容。很适合读取输入流的文本内容。
BufferedReader reader = new BufferedReader(fileReader);
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println("BufferReader输出:" + line);
}
reader.close();
}
/**
* 测试字节输出流
*/
@Test
public void fileOutputStreamTest() {
try {
// 创建字节输出输入流
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\82409\\Desktop\\error.log");
//创建字节输出流
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\82409\\Desktop\\newError.log");
byte[] buf = new byte[1024];
int hasRead = 0;
while ((hasRead = fileInputStream.read(buf)) > 0) {
fileOutputStream.write(buf, 0, hasRead);
}
fileInputStream.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 测试字符输出流
* @throws IOException
*/
@Test
public void FileWriteTest() throws IOException {
FileWriter fileWriter = new FileWriter("C:\\Users\\82409\\Desktop\\newErro.log");
fileWriter.write("不管风吹浪打 \n");
fileWriter.write("胜似闲庭信步 \n");
// 这里不关闭的,数据依旧在缓冲区,输出文件中是没有数据的。没有必要可以去记忆那些流有缓冲功能,只要正常关闭所有的输出流即可保证程序正常。
fileWriter.close();
}
根据流的角色来划分,可以分为节点流和处理流。可以从/向一个特定IO设备(比如磁盘、网络)读/写数据的流,成为节点流,节点流也被称为低级流。处理流则用于对一个已存在的流进行链接或封装,通过封装后的流来实现数据读/写功能。处理流也被称为高级流。
测试处理流
/**
* 使用处理流只需要在创建处理流时传入一个节点流作为构造器参数
*
* @throws IOException
*/
@Test
public void printStreamTest() throws IOException {
// 定义一个节点输出流
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\82409\\Desktop\\newErro.log");
// 使用PrintStream包装该节点输出流
PrintStream printStream = new PrintStream(fileOutputStream);
// 使用PrintStream执行输出
printStream.println("单纯试一下");
// 直接使用PrintStream输出对象
printStream.println(new IOStreamTest());
fileOutputStream.close();
printStream.close();
}
推回输入流:PushbackInputStream和pushBackReader
这两个推回输入流都带有一个推回缓冲区,当程序调用这两个推回输入流的unread()方法时,系统将会把指定数组的内容推回到该缓冲区里,而推回输入流每次调用read()方法时,系统将会把指定数组的内容推回到该缓冲区里,而推回输入流每次调用read()方法总是先从推回缓冲区读取,只有完全读取了推回缓冲区的内容后,但还没有装满read()所需的数组时才会从与那输入流中读取。
/**
* 测试推回输入流
* @throws IOException
*/
@Test
public void pushBackTest() throws IOException{
// 创建一个PushbackReader对象,指定退回缓冲区的长度为64
PushbackReader pushbackReader = new PushbackReader(new FileReader("C:\\Users\\82409\\Desktop\\newErro.log"),64);
char[] buf = new char[32];
// 用来保存上一次读取的字符串内容
String lastContent = "";
int hasRead = 0;
while ((hasRead = pushbackReader.read(buf)) > 0){
String content = new String(buf,0,hasRead);
System.out.println(content);
pushbackReader.unread((lastContent + content).toCharArray());
System.out.println(new String(buf,0,hasRead));
}
pushbackReader.close();
}
重定向标准输入/输出流
/**
* 测试重定向标准输出,将sout重定向到文件输出
*/
@Test
public void RedirectOutTest() throws IOException{
// 创建PrintStream输出流
PrintStream printStream = new PrintStream(new FileOutputStream("C:\\Users\\82409\\Desktop\\newErro.log"));
// 将标准输出重定向到printStream输出流
System.setOut(printStream);
System.out.println("我就试一下");
printStream.close();
}
/**
* 测试重定向标注输入
*/
@Test
public void RedirectInTest() throws IOException{
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\82409\\Desktop\\newErro.log");
System.setIn(fileInputStream);
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
System.out.println(scanner.next());
}
fileInputStream.close();
}
通过runtime的exec()从其他进程读取输出/写入
@Test
public void ReadFromProcessTest()throws IOException{
// 运行javac命令,返回运行该命令的子进程
Process p = Runtime.getRuntime().exec("javac");
/*
以p进程的错误流创建BufferedReader对象,这个错误流对本程序是输入流,对p进程则是输出流
*/
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String buff = null;
// 采取循环方式来读取p进程的错误输出
while ((buff = bufferedReader.readLine()) != null){
System.out.println(buff);
}
}
/*
在java程序中启动java虚拟机运行另一个java程序,并向另一个java程序中写入数据。
使用Runtime的exec执行java ReadStandard命令,该命令将运行ReadStandard类,并返回运行该程序的子进程;程序第二行获取process的输出流,程序将该输出流向process
*/
@Test
public void WriteToProcessTest() throws IOException{
// 运行java ReadStandard命令,并返回运行该命令的子进程
Process process = Runtime.getRuntime().exec("java ReadStandard");
// 以process进程的输出流创建PrintStream对象,这个输出流对本程序来说是输出流,对process进程来说是输入流
PrintStream printStream = new PrintStream(process.getOutputStream());
printStream.println("我还是要试一下");
printStream.close();
}
RandomAccessFile
它可以读取文件内容,也可以向文件输出数据。与普通输入/输出流不同的是,它支持任意访问,程序可以跳转到文件的任意地方来读写数据。如果程序需要向已存在的文件后追加内容,那么应该使用RandomAccessFile,局限是,他只能读写文件,不能读写其他IO节点。RandomAccessFile对象也包含了一个记录指针,用来表示当前读写出的位置,当程序新创建一个RandomAccessFile对象时,该对象的文件记录指针位于文件头(0),当读/写n个字节后,指针向后移动n个字节,RandomAccessFile也可以自由移动指针。
@Test
public void RandomAccessFileTest() throws IOException {
RandomAccessFile randomAccessFile = new RandomAccessFile("C:\\Users\\82409\\Desktop\\newErro.log", "r");
// 获取randomAccessFile指针位置
System.out.println("指针位置" + randomAccessFile.getFilePointer());
randomAccessFile.seek(3);
byte[] buf = new byte[1024];
int hasRead = 0;
while ((hasRead = randomAccessFile.read(buf)) > 0){
System.out.println(new String(buf,0,hasRead));
}
randomAccessFile.close();
}
@Test
public void AppendContentTest() throws IOException{
RandomAccessFile randomAccessFile = new RandomAccessFile("C:\\Users\\82409\\Desktop\\newErro.log", "rw");
// 将记录指针移动到文件最后
randomAccessFile.seek(randomAccessFile.length());
randomAccessFile.write("新填内容有了吗".getBytes());
randomAccessFile.close();
}
/**
* 向指定文件、指定位置插入内容
*/
public void insertContentTest(String fileName,long pos,String content) throws IOException{
// 新建临时文件
File temp = File.createTempFile("temp",null);
RandomAccessFile randomAccessFile = new RandomAccessFile(fileName,"rw");
FileOutputStream fileOutputStream = new FileOutputStream(temp);
FileInputStream fileInputStream = new FileInputStream(temp);
randomAccessFile.seek(pos);
// 将插入点后的内容加入临时文件保存
byte[] buf = new byte[1024];
int hasRead = 0;
while ((hasRead = randomAccessFile.read(buf)) > 0){
fileOutputStream.write(buf,0,hasRead);
}
// 插入内容
randomAccessFile.seek(pos);
randomAccessFile.write(content.getBytes());
while ((hasRead = fileInputStream.read(buf)) > 0){
randomAccessFile.write(buf,0,hasRead);
}
randomAccessFile.close();
fileInputStream.close();
fileOutputStream.close();
}