文件和流的基本用法
1. 文件的使用
1.1 文件的概念
简单来说,磁盘上保存的一切内容都是文件。
1.2 文件的操作
文件的表示方式:使用java.io.File类来表示。
用来判断的操作:
用来得到文件信息的操作:
用来创建删除文件的操作:
注意:File类对于文件的操作,仅仅只是对于文件本身的操作,不包含对于文件内容的操作,对于内容的操作叫做流。
1.3 File类基本创建
public static void main(String[] args) {
// 1.直接指定路径
File file = new File("e:"+File.separator+"1.txt");
// 2.指定目录的名称,文件的名称
File file2 = new File("C:/Users/admin/Desktop/aaa", "2.txt");
// 得到父目录
File parent = new File("C:\\Users\\admin\\Desktop\\aaa");
// 3.指定目录,文件的名称
File file3 = new File(parent, "3.txt");
System.out.println(file);
/*
在不同的系统中,路径的分隔符不一样,windows习惯用\,linux等系统习惯用/
在java代码中,特别是windows系统中,使用\或者/都可以,
但是\由于本身在Java中作为转义字符使用,所以需要使用\\
为了避免分割符造成的兼容性问题,Java中提供了应对的办法。
推荐使用File.separator,它表示得到当前系统相关的分割符
*/
//注意:无论提供的路径是否存在,File类都会创建成功,不会null
}
1.4 用来判断的操作
public static void main(String[] args) {
File file = new File("C:\\Users\\admin\\Desktop\\aaa\\3.txt");
File otherFile = new File("C:\\Users\\admin\\Desktop\\aaa\\4.txt");
// canExecute : 能否执行,只针对于linux之类系统有效,windows基本都返回true
boolean b = file.canExecute();
// 小技巧,如何执行windows中的exe文件
/*
try {
Runtime runtime = Runtime.getRuntime(); // 得到执行环境
runtime.exec("C:\\Program Files (x86)\\Tencent\\QQ\\Bin\\QQScLauncher.exe");
} catch (Exception e) {
e.printStackTrace();
}
*/
boolean b1 = file.canRead(); // 判断文件是否可读
boolean b2 = file.canWrite(); // 判断文件是否可写
boolean b3 = file.exists(); // 判断文件是否存在
boolean b4 = file.isDirectory(); // 判断文件是否目录(文件夹)
boolean b5 = file.isFile(); // 判断是否一个文件
boolean b6 = file.isHidden(); // 判断是否隐藏
int result = file.compareTo(otherFile); // 比较两个文件pathname,相等为0
}
1.6 得到文件信息的操作
public static void main(String[] args) {
File file = new File("C:\\Users\\admin\\Desktop\\aaa\\3.txt");
String absolutePath = file.getAbsolutePath(); // 获得文件绝对路径(包含盘符)
long totalSpace = file.getTotalSpace(); // 得到当前文件所对应磁盘空间总大小
long freeSpace = file.getFreeSpace(); // 得到当前文件所对应磁盘空间剩余空间大小
long usableSpace = file.getUsableSpace(); // 得到当前文件所对应磁盘空间可用空间大小
String name = file.getName(); // 得到文件的名称
String parent = file.getParent(); // 得到文件的父文件夹的路径
File parentFile = file.getParentFile(); // 得到文件的父文件夹File对象
String path = file.getPath(); // 得到当前文件路径
}
1.7 操作文件的操作
public static void main(String[] args) {
File file = new File("c:\\Users\\admin\\Desktop\\aaa\\bbb\\ccc");
/*
* 由于文件操作会根据当前环境,而导致操作不成功
* 所以需要手动的处理异常
*/
try {
// 创建一个新的文件
// 如果路径找不到,会抛出异常,系统找不到指定的路径
// 如果文件已经存在,可能导致创建无效(建议判断是否存在)
boolean b = file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
// 如果文件存在,则删除并返回true,如果不存在则返回false
boolean b1 = file.delete(); // 删除一个文件,如果删除一个文件夹,需要空的文件夹才能删除
System.out.println(b1);
long len = file.length(); // 得到文件内容字节数
System.out.println(len);
// 文件夹操作
String [] paths = file.list(); // 得到文件夹中文件名称(短名称)的列表
for (String string : paths) {
System.out.println(string);
}
File [] files = file.listFiles(); // 得到文件夹中文件的列表
for (File file2 : files) {
System.out.println(file2.getPath());
}
boolean b2 = file.mkdir(); // 创建一个文件夹
System.out.println(b2);
boolean b3 = file.mkdirs(); // 创建文件夹,如果路径中包含不存在文件夹,一起创建
System.out.println(b3);
File destFile = new File("c:\\Users\\admin\\Desktop\\aaa\\bbb\\3.txt");
file.renameTo(destFile); // 同一个文件夹,则重命名,不同的文件夹,则移动文件
}
测试:读取一个文件夹,将文件夹中的内容结构复制到另一个文件夹中。
public static void main(String[] args) {
// 复制一个文件夹aaa中的结构到另一个文件夹aaaa中(包含文件夹中的文件和子文件夹里面的文件)
/*分解步骤:
1. 递归遍历源文件夹中的所有文件(包含子文件夹中的文件)
2. 在递归的过程中,判断当前文件是文件夹还是文件,如果是文件夹,则创建文件夹,如果是文件,则创建文件(在目标地址创建)
*/
String srcPath = "C:\\Users\\admin\\Desktop\\img";
String descPath = "C:\\Users\\admin\\Desktop\\aaaa";
File srcFile = new File(srcPath); // 创建一个源文件的目录
File descFile = new File(descPath); // 创建一个目标文件的目录
if(!descFile.exists()) { // 如果目标文件夹不存在
descFile.mkdirs(); // 创建一个文件夹
}
if(srcFile.isDirectory()) { // 判断是否目录
getListFile(srcFile, descFile);
}
}
/**
* 遍历文件夹,复制内容
* @param directory
*/
public static void getListFile(File directory, File descFile) {
File [] list = directory.listFiles(); // 得到当前源文件夹中的所有文件
for (File file : list) {
// 创建一个File对象
File newFile = new File(descFile, file.getName());
if(file.isFile()) { // 如果是一个文件
try {
// 创建一个文件
newFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}else {
// 创建一个文件夹
boolean b = newFile.mkdir();
if(b) {// 继续遍历文件夹中的内容,复制到目标文件夹中
getListFile(file, newFile);
}
}
}
}
流
2.1 流的基本概念
简单来说,流是指操作文件的通道(管道)可以称为流。
2.2 流的分类
根据流向分为输入流和输出流。 流的流向是指的内存。 读:把磁盘中的数据流向到内存中。输入 写:把内存中的数据流向到磁盘。输出
根据每次传输的字节大小分为字节流和字符流。
2.3 输入流和输出流
InputStream和OutputStream
// read()读取一个字节
// read(buffer) 读取多个字节,
// read(buffer, off, len) 读取多个字节,从off开始,读取len长度
// skip 跳过多个字节,然后读取
// available // 有效字节长度
public static void main(String[] args) {
readBuffer();
}
/**
* 每次读取多个字节来读取文件
*/
public static void readBuffer() {
File file = new File("C:\\Users\\admin\\Desktop\\aaa\\a.txt");
try {
// 创建一个文件的输入流对象
InputStream is = new FileInputStream(file);
// is.skip(5); // 跳过5个字节
int a = is.available();
System.out.println("a=====" + a);
// 循环终止条件,当读取到字节值为-1时
byte [] buffer = new byte[1024];
int i; // 当次读取有效字节长度
while((i = is.read(buffer)) != -1) {
System.out.print(new String(buffer, 0, i)); // 字节内容,起始位置,长度
}
System.out.println("====end====");
// 关闭流
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 每次读取一个字节来读取文件
*/
public static void readByte() {
File file = new File("C:\\Users\\admin\\Desktop\\aaa\\a.txt");
try {
// 创建一个文件的输入流对象
InputStream is = new FileInputStream(file);
// 循环终止条件,当读取到字节值为-1时
int i;
while((i = is.read()) != -1) {
System.out.print((char)i);
}
// 关闭流
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
IO流
1.1 输出流
OutputStream,作用主要是用来将内存中数据进行输出。
/**
* 使用基础的输出流
* @author admin
* write(int) 写入一个ASCII码
* write(byte []) 写入一个字节数组
* write(byte [] bytes, int off, int len)从一个字节数组的第off位开始,写入len个字节
* flush() 刷新,清空缓冲区,写入到目标
* close() 关闭流,会在关闭前清空缓冲区
*/
public class MyOutputStreamDemo {
public static void main(String[] args) {
// 1. 将一段文字写入到文件
String destPath = "C:\\Users\\admin\\Desktop\\aaa\\b.txt";
File file = new File(destPath);
try {
// 创建一个输出流
OutputStream os = new FileOutputStream(file, true); // 如果不写或者写false,会覆盖原来的内容,true则表示追加在后面
os.write(51); // 写入51(ASCII码,代表数字3)
os.write(13); // 相当于/r
os.write(10); // 相当于/n
String s = "Hello, world";
byte [] bytes = s.getBytes(); // 得到字符串的字节数组
os.write(bytes);
os.flush(); // 直接清空缓冲区,写入磁盘
os.close(); // 关闭流
/*
当输出流写入磁盘数据时,并不是直接写入磁盘,而是先写入缓冲区,再将缓冲区数据写入磁盘。
将缓冲区数据写入磁盘时机常见有3种:
1. 调用flush刷新缓冲区
2. 使用close关闭流
3. 缓冲区使用满时
*/
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.2 字符流
在处理数据时,以一个字符为单位进行处理。 FileReader和FileWriter
// FileReader用法:
public static void main(String[] args) {
readChars();
}
/**
* 读取一个字符
*/
public static void readChar() {
String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
try {
// 创建一个字符输入流对象
FileReader reader = new FileReader(srcPath);
int i = -1; // 定义读取的内容
while((i = reader.read()) != -1) { // 判断内容不为-1,则循环读取
System.out.println((char)i); // 使用char来显示内容,每次读取一个char(相当于2bytes),字节流每次读取一个byte
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 读取多个字符
*/
public static void readChars() {
String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
try {
// 创建一个字符输入流对象
FileReader reader = new FileReader(srcPath);
char [] chars = new char[1024]; //定义一个读取内容的char的数组
int i = -1; // 定义读取的长度
while((i = reader.read(chars)) != -1) { // 判断长度不为-1,则循环读取
String s = new String(chars, 0, i); // 将读取的实际内容组成一个字符串
s = new String(s.getBytes("gbk"), "utf-8"); // 将原本的文字使用gbk的形式拆解成字节,然后以utf-8的形式重组成字符串
System.out.println(s); //
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
FileWriter用法:
/**
* 字符输出流
* @author admin
* write(int) 将一个char型内容写入, 应该小于65536, 超出了会循环
* write(char[])将一个char数组的内容写入
* write(String)将一个字符串写入
* 如果在代码中出现了中文,要将此中文写入文本,会自动根据当前类代码对应的编码格式来写入文件,并且会将文件的格式也改成此编码
* 例如当前类java文件是gbk的编码,如果将哈哈哈写入文本,会将文本的编码格式也转换成gbk(在微软系统中对应的ANSI)
*/
public class MyFileWriterDemo {
public static void main(String[] args) {
String destPath = "C:\\Users\\admin\\Desktop\\aaa\\1.txt";
try {
FileWriter writer = new FileWriter(destPath, true); // 创建字符输出流
writer.write(65548-65536); // 写入一个int型数据(会转换成char)
char [] chars = {'A', 'B', '西'}; // 写入char数组数据,注意中文的编码
writer.write(chars);
writer.write("哈哈哈"); // 写入字符串
writer.flush();
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.3 转换流
一般来说,转换流是指将字节流转换字符流,以便解决编码问题。 InputStreamReader, OutputStreamWriter
/**
* 转换流
* @author admin
*
*/
public class MyInputStreamReaderDemo {
public static void main(String[] args) {
write();
}
/**
* 使用转换流写文件,并设置字符集
*/
public static void write() {
String destPath = "C:\\Users\\admin\\Desktop\\aaa\\1.txt";
try {
OutputStream os = new FileOutputStream(destPath, true);// 创建一个字节输出流
OutputStreamWriter writer = new OutputStreamWriter(os, "utf-8"); // 创建一个转换流, 并设置字符集
writer.write("面对疾风吧");
writer.flush();
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 使用转换流读取文件,并设置字符集
*/
public static void read() {
String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\1.txt";
try {
InputStream is = new FileInputStream(srcPath); // 创建一个字节流
InputStreamReader reader = new InputStreamReader(is, "utf-8"); // 使用上面的字节流创建一个字符转换流,并且设置文件的编码
char [] chars = new char[1024];
int len = -1; // 得到有效字符长度
// 读取文件
while((len = reader.read(chars)) != -1) {
String s = new String(chars, 0, len);
System.out.println(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.4 缓冲流
带有缓冲的流。
/**
* 缓冲流
* @author admin
*/
public class MyBufferedDemo {
public static void main(String[] args) {
bufferedWriter();
}
/**
* 带缓冲的字符的输出流
*/
public static void bufferedWriter() {
String destPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
try {
// 通过转换流设置字符集,创建一个追加内容的缓冲输出字符流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destPath, true), "utf-8"));
bw.write("左手画一条龙");
bw.newLine(); // 换行
bw.write("右手画一道彩虹");
bw.flush();
bw.close();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 带缓冲的字符的输入流
*/
public static void bufferedReader() {
String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\3.txt";
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(srcPath), "utf-8")); // 通过转换流设置字符集,创建一个缓冲流
String str = reader.readLine(); // 读取一行
System.out.println(str);
reader.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 与字节输出流代码操作上一样。
* 从原理上来说,原来的字节输出流每次写入内容,会写入到系统的缓冲区,而带缓冲的输出流每次在写入的时候,只是把内容写入到了当前流的缓冲区,当流的缓冲区满了,才会写入到系统的缓冲区
*/
public static void bufferedOutput() {
String destPath = "C:\\Users\\admin\\Desktop\\aaa\\a.txt";
try {
OutputStream os = new FileOutputStream(destPath);
BufferedOutputStream bos = new BufferedOutputStream(os);
bos.write(53);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 缓冲输入字节流由于自带缓冲,所以可以在读取的时候设置标记,并回档到标记的地方
*/
public static void bufferedInput() {
String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\a.txt";
try {
InputStream is = new FileInputStream(srcPath); // 创建一个字节输入流
BufferedInputStream bis = new BufferedInputStream(is); // 创建一个缓冲输入流
int i = bis.read(); // 读取一个字节
bis.mark(9); // 在当前字节设置一个临时标记,记录当前位置,实际是在buffer中记录的, mark中的参数使用当前文件能读取的最大字节数
int j = bis.read(); // 读取一个字节
System.out.println((char)i + "===" +(char)j);
bis.reset(); // 回档到原来设置标记的地方开始重新读取内容
i = bis.read();
j = bis.read();
System.out.println((char)i + "===" + (char)j);
bis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.5 内存流
1.6 标准输入输出流
1.7 对象流和序列化
对象流是操作对象的流,可以将对象直接写入文件,或者在文件中读取对象。 序列化是指将对象转成有序列的流的方式,反序列化将文件内容有序的转换成对象的方式。 对于Java来说,要实现序列化的要求很简单,只需要实现java.io.Serializable接口即可,而且此接口中没有任何方法。
序列化id应该在项目中是唯一的,它的作用是保证当前项目中对象被序列化后,可以安全的反序列化,如果在反序列化时,id不一致,则会出现异常。
transient 关键字修饰属性,表示在序列化时不会将该关键字修饰的属性序列化,那么反序列化时该属性值为空。
public class Student implements java.io.Serializable{
private static final long serialVersionUID = 6554237497611252685L;
private int id;
private String name;
private transient Integer age; // 表示该属性不会被序列化
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
/**
* 对象流
* @author admin
* 如果使用对象流,需要对象对应的类实现序列化接口,如果没有实现,则会出现java.io.NotSerializableException: 异常
*/
public class MyObjectStreamDemo {
public static void main(String[] args) {
// writeObject();
readObject();
}
/**
* 将对象读入到内存
*/
public static void readObject() {
String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\2.txt";
try {
// 创建一个对象读取的流
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(srcPath));
// 读取对象
Student stu = (Student) ois.readObject(); // 并不能循环读取,只能读取一次, 如果有多个对象,可以存入集合再保存
System.out.println("id:" + stu.getId() + ", name:" +stu.getName() + ",age:" + stu.getAge());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 将对象写入文件
*/
public static void writeObject() {
String srcPath = "C:\\Users\\admin\\Desktop\\aaa\\2.txt";
try {
// 创建一个对象流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(srcPath));
// 创建一个对象(需要实现序列化接口)
Student stu = new Student();
stu.setId(1);
stu.setName("张三");
stu.setAge(20);
// 写入文件
oos.writeObject(stu);
oos.flush();
oos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
网友评论