IO:输入流InputStream 输出流OutputStream
通常在软件开发项目中,长期保存数据的办法主要有两类:一类是使用数据库保存,相关的内容会在本书的 JDBC 一章做详细介绍;另外一类就是把数据保存在文件中,这也是本章讲解的重点——使用 IO 和 XML 存取数据。
Java中的IO流是输⼊输出流。输⼊流指的是将数据以字符或字节形式从外部媒介⽐如⽂件、数据库等读取到内存中所以也分为字符输⼊流和字节输⼊流。 输出流指的是将内存中的数据写⼊外部媒介,也分为了字符输出流和字节输出流。举个简单的例子可以理解为将输⼊和输出两个端点看作是两个⼯⼚,⼯⼚之间需要互相运输货物,⽽流则是两⼯⼚之间的公路,没有公路就不能互相运输,⾄于字符,字节和⼆进制则可以看作是运输的⽅式和单位⼤⼩。
File
类在java.io
包下
一、关于file类的 API
file.isFile()==true?"文件":"非文件";
file.isDirectory()==true?"目录":"非目录";
相对路径:file.getPath();
绝对路径:file.getAbsolutePath();
相对路径和绝对路径:
- 如果file("绝对路径"):getPath()和getAbsolutePath()的打印结果一致,打印的都是绝对路径
- 如果file("相对路径"):getPath()打印相对路径,getAbsolutePath()的打印绝对路径
文件名称:file.getName();
文件大小:file.Length();单位是字节
创建文件:file.createNemFile();
删除文件:file.Delete(); //彻底删除
判断文件是否存在:file.exists();
针对以上方法的实现代码:
import java.io.*;
public class TestFile{
public static void main(String args[]) throws IOException {
System.out.print("文件系统根目录");
for (File root : File.listRoots()) {
//format方法以格式化形式输出字符串
System.out.format("%s ", root);
}
System.out.println();
showFile();
}
public static void showFile() throws IOException{
//创建File类对象file,注意使用转义字符 `\`
File f = new File("/home/project/Vehicle.java");
File f1 = new File("/home/project/Vehicle1.java");
//当不存在该文件时,创建一个新的空文件
f1.createNewFile();
System.out.format("输出字符串:%s%n", f);
System.out.format("判断File类对象是否存在:%b%n", f.exists());
//%tc,输出日期和时间
System.out.format("获取File类对象最后修改时间:%tc%n", f.lastModified());
System.out.format("判断File类对象是否是文件:%b%n", f.isFile());
System.out.format("判断File类对象是否是目录:%b%n", f.isDirectory());
System.out.format("判断File类对象是否有隐藏的属性:%b%n", f.isHidden());
System.out.format("判断File类对象是否可读:%b%n", f.canRead());
System.out.format("判断File类对象是否可写:%b%n", f.canWrite());
System.out.format("判断File类对象是否可执行:%b%n", f.canExecute());
System.out.format("判断File类对象是否是绝对路径:%b%n", f.isAbsolute());
System.out.format("获取File类对象的长度:%d%n", f.length());
System.out.format("获取File类对象的名称:%s%n", f.getName());
System.out.format("获取File类对象的路径:%s%n", f.getPath());
System.out.format("获取File类对象的绝对路径:%s%n",f.getAbsolutePath());
System.out.format("获取File类对象父目录的路径: %s%n", f.getParent());
}
}
测试结果如下所示:
System.out.format(format, args)
表示使用指定格式化字符串输出,其中 format
参数为格式化转换符。关于转换符的说明如下表所示:
转换符 | 说明 |
%s | 字符串类型 |
%c | 字符类型 |
%b | 布尔类型 |
%d | 整数类型(十进制) |
%x | 整数类型(十六进制) |
%o | 整数类型(八进制) |
%f | 浮点类型 |
%e | 指数类型 |
%% | 百分比类型 |
%n | 换行符 |
%tx | 日期与时间类型( x 代表不同的日期与时间转换符) |
关于路径分隔符的使用:
import java.io.File;
public class TestFileSeparator {
public static void main(String[] args) {
System.out.println("PATH分隔符:" + File.pathSeparator);
System.out.println("路径分隔符:" + File.separator);
}
}
二、流
流:是一种FIFO(先进先出)的数据结构
(一)按照流向(以内存为参照点)分:
输入流 输出流
- 1、输入流(java.io.InputStream抽象类/Reader)-->表示字节流形式的输入流/字符流形式的输入流
- 就是把一个文件通过输入流读入到内存中去
import java.io.*;
public class test{
public static void main(String args[]) {
InputStream in = null;
try {
in = new FileInputStream(new File("d:/test.txt"));
System.out.println(in.available());
//in.available(),表示文件的大小
byte[] buf = new byte[in.available()];
in.read(buf); //将文件test.txt内容读取到buf中,即内存中去
//因为buf现在是一个字节数组,所以先要转换成字符串才能显示,buf-->String
System.out.println(new String(buf));//打印文件里面的内容
}catch(Exception e){
e.printStackTrace();
}finally {
//流一般是要关闭的,而且一般放在finally里面
try {
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
- 2、输出流(java.io.OutputStream抽象类/Writer)-->表示字节流形式的输出流/字符流形式的输出流
- 就是把内存中的内容通过输出流写入到文件中去
import java.io.*;
public class test{
public static void main(String args[]) {
OutputStream out = null;
try {
out = new FileOutputStream(new File("d:/test.txt"));
out.write("重新输入的······".getBytes()); //内存-->test.txt
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
- 文件的复制
在文件复制过程中会出现以下几种情况:
因为文件有可能过大,所以需要分次进行读取,而假设每次读取的字节数为10,则最后一次读取完之后,下次想要读取时则返回-1(len)时,也就是已经将文件中的内容全部读取到内存中去了。。
总体的复制过程就是每次读取到内存中,然后再输出,再进行下一次的读取,,上次读取完10个字节后,下次读取时,该10个字节会完全覆盖上次读取时的10个字节,,,意思就是内存(缓冲区的大小是10个字节),但是最后一次复制时文件中就只剩下2个字节(比如qw)时,则会将上次缓冲区(比如1234567890)的8个字节作为最后一次的复制内容(即qw34567890),,出现这种情况的解决方法是:在最后一次输出时,输出从0开始,到最后一次热read()的返回值len;
import java.io.*;
public class test{
//test.txt-->内存-->out
public static void main(String args[]) {
OutputStream out = null;
InputStream in = null;
try {
in = new FileInputStream(new File("d:/test.txt"));//这里也可以传输图片、视频等其它文件
out = new FileOutputStream(new File("d:/new.txt"));//这里也可以传输图片、视频等其它文件
//test.txt-->内存
//开辟10个字节的内存数组
byte[] buf = new byte[10];
int len = -1;
while ( (len=in.read(buf))!=-1){
//内存-->out
out.write(buf,0,len);
}
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}catch (IOException e){
e.printStackTrace();
}finally {
try {
if(in !=null)in.close();
if(out !=null)out.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}
- 以上三种都是使用字节流实现文件的输入/输出以及文件的复制
说明:在while循环中 分批次传输时,字节流使用的缓冲区是byte[ ]类型的数组,字符流使用的缓冲区是char[ ]类型的数组
(二)按照处理单位分:
- 1、字节流:就是将文件内容以字节形式进行传输,1字节-->8bit,二进制可以传输任何类型的数据,因此字节流也可以传输任何类型的数据。(其中包括文件、图片、视频、压缩包等等,基本上都是除了文本文件以外的所有文件)
FileInputStream、 FileOutputStream //既是字节流也是输入输出流(之前在复制文件时用到过)
- 2、字符流:是16位的unicode字符流(只用于处理字符,文本文件)
Reader/writer
每次往内存中读取一次就拼接一次(就是每次把内存中的读取数据拼接成完整的数据,可用一个字符串[StringBuffer]来拼接)
import java.io.*;
public class test{
//简介.txt-->内存-->拼接-->替换占位符-->完整简介
public static void main(String args[]) {
//文件-->内存(reader)
Reader reader =null;
Writer writer =null;
try {
reader = new FileReader(new File("d:/简介.txt"));
writer = new FileWriter(new File("d:/完整简介.txt"));
char[] buf = new char[4];
StringBuffer sb = new StringBuffer();
int len = -1;
while ((len = reader.read(buf))!=-1){
//内存-->拼接
sb.append(buf,0,len);
}
//内存-->拼接-->替换占位符
String content = sb.toString();//将StringBuffer()利用toString()转换成String
/*content=content.replace("{name}","王福昌");
content=content.replace("{place}","甘肃");
content=content.replace("{课程}","java");*/
//也可以简写为:
content=content.replace("{name}","王福昌")
.replace("{place}","甘肃")
.replace("{课程}","java");
//将替换后的内容输出到新文件中:替换占位符-->完整简介
writer.write(content);
System.out.println("成功");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}finally {
try {
if(reader!=null)reader.close();
if(reader!=null)writer.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}