IO流与文件操作
文件操作
文件:硬盘上的文件,txt docx 电影 图片
常见的文件操作
import java.io.File;//大多数文件io操作的包
import java.io.IOException;
public class IO {
public static void main(String[] args) {
//file可以放一个不存在的路径 file:文件、目录、文件
File file = new File("d:/abc.txt");//new一个新文件
System.out.println("相对路径:"+file.getPath());
System.out.println("绝对路径:"+file.getAbsolutePath());
System.out.println("文件名称:"+file.getName());
System.out.println("文件大小:"+file.length());//单位字节
//创建一个文件,没有就创建,有就删除
boolean flag = file.exists();//判断是否存在
System.out.println(file.isFile() == true ? "文件" : "非文件");
System.out.println(file.isDirectory() == true ? "目录" : "非目录");
if (flag){
file.delete();//彻底删除
System.out.println("删除成功");
}else{
try {
file.createNewFile();//创建文件
System.out.println("创建成功");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
-
如果File(“绝对路径”):
getPath()
和getAbsolutePath()
的结果一致,打印的都是绝对路径 -
如果File(“相对路径”):
getPath()
相对路径,getAbsolutePath()
绝对路径
IO流
IO流:是一种FIFO(先进先出)的数据结构
打开流后不要忘了关闭close
,否则会让数据卡在管道(缓冲区)里,导致数据丢失
flush
可以把缓冲区里的东西冲出去,调用close
实际上先调用了flush
按流向分:
-
输入流:
InputStream
(字节流)顶层抽象类Reader
(字符流)顶层抽象类 -
输出流:
OutputStream
(字节流)顶层抽象类Writer
(字符流)顶层抽象类
按照处理单元:
- 字节流:(以字节复制任何东西)字节流就是将内容转为字节形式传输,1字节是8位二进制,二进制可以传输任何东西,所以字节也可以传输任何东西,文件的后缀名无所谓,重要的是他的字节内容(内容不变)
- 字符流:文件内容变成字符,只能传输字符(文本文件),其他形式会有乱码,16位的
Unicode
处理文本文件
字节流的文件操作
//输入流操作
//实现类FileInputStream FileOutputStream
public static void test01() {
InputStream in = null;
try {
in = new FileInputStream("d://hh.txt");//创建输入流对象
byte[] buf = new byte[in.available()];//获取文件大小(这里采用一次全部读入,下面的实战会使用循环读入)
in.read(buf);//读取文件内容
System.out.println(new String(buf));//打印读出的内容
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (in != null) in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
//输出流操作
public static void test02() {
String need = "abandon";
OutputStream out = null;
File file = new File("D://hh.txt");
if (!file.exists()) {//检查文件是否存在
try {
file.createNewFile();
System.out.println("文件不存在,创建成功");
}
catch (IOException e) {
e.printStackTrace();
}
}
try {
out = new FileOutputStream(file);//打开输出流
out.write(need.getBytes());//通过输出流向文件内写入字节
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (out != null) out.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
实战演练:运用IO流传输复制文件
public static void test03() {
InputStream in = null;
OutputStream out = null;
File file = new File("D://Study//copy.txt");
if (!file.exists()) {
try {
file.createNewFile();
}
catch (IOException e) {
e.printStackTrace();
}
}
try {
in = new FileInputStream("D://Study//target.txt");//预先准备好一个需要拷贝的文件
out = new FileOutputStream(file);
int length = -1;
byte[] buf = new byte[10];
while ((length = in.read(buf)) != -1) {
out.write(buf, 0, length);//控制写入的内容长度,否则会因为最后一次比10个字节小的情况没有完全覆盖上一次内容,而导致多写入一部分
}
}
catch (Exception e) {
e.printStackTrace();
}
finally {
try {
if (out != null) out.close();
if (in != null) in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
字符流的文件操作
传输改变文件测试,细节与字节流中的测试基本一致
/*
实现类FileReader FileWriter
原信息:你好我是{name},目前工作单位{enterprise},个人微信{weixin}
替换占位符,并且输出
新信息:你好我是菜鸡,目前工作单位啃老,个人微信114514
*/
public static void test04(){
FileReader in = null;
FileWriter out = null;
try {
in = new FileReader("D://Study//abc.txt");
out = new FileWriter("D://Study//xyz.txt");//以字节流的形式打开输入输出流
char[] buf = new char[4];//字符流缓冲区是字符数组
StringBuffer sb = new StringBuffer();
int length = -1;
while ((length = in.read(buf)) != -1) {
sb.append(buf,0,length);
}
String content = sb.toString();
content = content.replace("{name}","菜鸡").replace("{enterprise}","啃老").replace("{weixin}","114514");
//字符串的练习操作
out.write(content);
System.out.println(content);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (out != null) out.close();
if (in != null) in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
缓冲流
作用:加快读写操作速度
在已有流的基础上再打开一层(下面的流基本都有该特性,即更强大的包装流)缓冲流,关闭流时遵循先输出后输入,先外后内的原则
/*
自带缓冲区的字符流:缓冲区大小,每次读一行
实现类BufferedReader BufferedWriter(字符流) BufferedInputStream BufferedOutputStream(字节流)
*/
public static void test04() {
FileReader in = null;
FileWriter out = null;
BufferedReader br = null;
BufferedWriter bw = null;
try {
in = new FileReader("d:/abc.txt");
out = new FileWriter("d:xyz.txt");
br = new BufferedReader(in);//这里展示一下字符缓冲流
bw = new BufferedWriter(out);
//再打开一层带缓冲区的流
StringBuffer sb = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {//打开后可以直接一行一行的读
sb.append(line);
}
String content = sb.toString();
content = content.replace("{name}", "张三").replace("{enterprise}", "家里蹲").replace("{weixin}", "1110");
out.write(content);
System.out.println(content);
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
//先关闭输出再关闭输入流,从外往内关闭
if (bw != null) bw.close();
if (br != null) bw.close();
if (out != null) out.close();
if (in != null) in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
二进制流(数据流)
只需将字节流加一层二进制流的打开即可
//二进制流
//实现类DataInputStream DataOutputStream
public static void test03() {
InputStream in = null;
OutputStream out = null;
InputStream dataInput = null;
OutputStream dataOutput = null;
try {
in = new FileInputStream("d:/abc.txt");
dataInput = new DataInputStream(in);//将字节流转换成二进制流
out = new FileOutputStream("d:xyz1.txt");
dataOutput = new DataOutputStream(out);//将字节流转换成二进制流
byte[] buf = new byte[10];
int len = -1;
while ((len = dataInput.read(buf)) != -1) {//通常使用二进制流时是为了用它读入不同类型数据的能力,如readInt(),readDouble()方法等等,写入同理,写入相应类型的数据可直接进行转换,这里就不进行了
dataOutput.write(buf, 0, len);
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (dataOutput != null) dataOutput.close();
if (dataInput != null) dataInput.close();
if (out != null) out.close();
if (in != null) in.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
转换流
作用:指定编码形式以解决直接用字符流读取文件内容时的乱码问题
-
InputStreamReader
将字节流转换字符流public static void test07() { try { InputStream in = new FileInputStream("D://Study//hh.txt"); InputStreamReader hh = new InputStreamReader(in, StandardCharsets.UTF_8);//字节读入和需要转换的编码形式,读取文件内容同上一部分中的操作 hh.close(); in.close(); } catch (IOException e) { throw new RuntimeException(e); } }
-
OutputStreamWriter
将字节流转换成字符流public static void test07() { try { OutputStream out = new FileOutputStream("D://Study//hh.txt"); OutputStreamWriter hh = new OutputStreamWriter(out, StandardCharsets.UTF_8);//格式同上 //hh.write("基尼泰美~~"); hh.close(); out.close(); } catch (IOException e) { throw new RuntimeException(e); } }
打印流
-
PrintStream
字节打印流public static void test05() { //终端打印write方法 OutputStream out = new PrintStream(System.out);//顶层为OueputStream try { out.write("hh".getBytes());//需要获取其字节输出防止乱码 //out.close();标准输出流不需要手动关闭 } catch (IOException e) { throw new RuntimeException(e); } //直接打印到相应的文件里 try { PrintStream dd = new PrintStream("D://Study//hh.txt"); System.setOut(dd);//重定向(打印流的应用):改变标准输出流的输出方向 System.out.println("hh123"); dd.close(); } catch (FileNotFoundException e) { throw new RuntimeException(e); } }
-
PrintWriter
字符打印流public static void test06() { PrintWriter out = new PrintWriter(System.out);//顶层为Writer out.println("hh"); //out.close();标准输出流不需要手动关闭 try { PrintWriter printWriter = new PrintWriter(new FileWriter("D://Study//hh.txt")); printWriter.print("manbaout"); printWriter.close(); } catch (IOException e) { throw new RuntimeException(e); } }
对象流(序列化流)
作用:将前面各种流没办法操作的对象进行读取或存储(在文件或网络中传输)
先准备一个实现Serializable
接口的Person
类(必须实现该接口否则无法将其对象进行序列化相关操作)
该接口内部无任何需要实现的抽象方法,只是一个标记接口,给编译器看的提醒它要进行序列化
public class Person implements Serializable {
private String account;
private String name;
private String password;
public Person() {
}
public Person(String account, String name, String password) {
this.account = account;
this.name = name;
this.password = password;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Person{" +
"account='" + account + '\'' +
", name='" + name + '\'' +
", password='" + password + '\'' +
'}';
}
}
-
ObjectInputStream
对象字节输出流(序列化流)(把对象写到文件中去)public static void test08() { Person person = new Person("0001", "QQ", "1234"); try (OutputStream out = new FileOutputStream("D://Study//hh.txt"); ObjectOutputStream obj = new ObjectOutputStream(out)){ obj.writeObject(person); System.out.println("序列化成功"); } catch (IOException e) { throw new RuntimeException(e); } } /*这是文件中的内容,是一种给机器看的写法 sr TestStream.Person擛铲氖2? L accountt Ljava/lang/String;L nameq ~ L passwordq ~ xpt 0001t QQt 1234 tips:可以发现一个不妥之处,实际开发中这样写会把密码也序列化了,黑客随便一黑就能get到用户密码,显然不够安全 所以就有了相应的关键字 transient 将这个关键字赋给类中不想序列化存储的变量即可让它出局,eg.private transient String password; */
-
ObjectOutputStream
对象字节输入流(反序列化流)(将对象从文件中读出来)public static void test08() { try (InputStream in = new FileInputStream("D://Study//hh.txt"); ObjectInputStream obj = new ObjectInputStream(in)){ Person myperson = (Person)obj.readObject();//注意读出来的数据进行强制转化 System.out.println(myperson); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException(e); } } //当有多个对象,在进行序列化存储时可以操作用ArrayList集合进行存储,它已经实现过Serializable接口
关于IO流主要有这些分类,需要我们熟练掌握的其实也就是最开始的字节流操作和序列化流,还有打印流的重定向,在学完Java进行实际开发时似乎会用的比较频繁,本文到这里就结束了!!感谢阅读