2 I/O
2.1 文件对象
2.1.1 创建一个文件对象
/**
*
* @author yrf
* D盘下创建abc.txt 内容:aaa
*
*/
public class IOTest {
public static void main(String[] args) {
// 绝对路径
File f1=new File("D:/test/abc.txt");
System.out.println("当前文件是:"+f1); // 当前文件是:D:\test\abc.txt
// 文件是否存在
System.out.println(f1.exists()); // true
// 文件是否是文件夹
System.out.println(f1.isDirectory());// false
// 是否是文件
System.out.println(f1.isFile()); // true
// 文件的长度
System.out.println(f1.length()); // 3
// 文件最后修改时间
long updateLastTime = f1.lastModified();
Date date=new Date(updateLastTime);
SimpleDateFormat sdf =new SimpleDateFormat("yyyy-MM-dd E HH:mm:ss SSS");
System.out.println("最后修改时间:"+sdf.format(date)); //最后修改时间:2018-08-14 星期二 17:01:15 116
// f1.setLastModified(0);
//文件重命名 renameTo方法用于对物理文件名称进行修改,但是并不会修改File对象的name属性。
File f2=new File("D:/test/abcd.txt"); //true
System.out.println(f1.renameTo(f2));
}
}
2.2 文件常用方法
public class IOTest {
public static void main(String[] args) {
// 绝对路径
File f=new File("D:/test/oracletest");
// 以字符串数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
f.list();
// 以文件数组的形式,返回当前文件夹下的所有文件(不包含子文件及子文件夹)
File[]fs= f.listFiles();
// 以字符串形式返回获取所在文件夹
f.getParent();
// 以文件形式返回获取所在文件夹
f.getParentFile();
// 创建文件夹,如果父文件夹skin不存在,创建就无效
f.mkdir();
// 创建文件夹,如果父文件夹skin不存在,就会创建父文件夹
f.mkdirs();
// 创建一个空文件,如果父文件夹skin不存在,就会抛出异常
try {
f.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 所以创建一个空文件之前,通常都会创建父目录
f.getParentFile().mkdirs();
// 列出所有的盘符c: d: e: 等等
f.listRoots();
// 刪除文件
f.delete();
// JVM结束的时候,刪除文件,常用于临时文件的删除
f.deleteOnExit();
}
}
2.3 什么是流
什么是流(Stream),流就是一系列的数据
比如读取文件的数据到程序中,站在程序的角度来看,就叫做输入流
输入流: InputStream
输出流:OutputStream
2.4 字节流
InputStream字节输入流
OutputStream字节输出流
用于以字节的形式读取和写入数据
以字节流的形式读取文件内容
InputStream是字节输入流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileInputStream 是InputStream子类,以FileInputStream 为例进行文件读取
public class IOTest {
public static void main(String[] args) throws IOException {
// 绝对路径 创建文件 内容 aaa
File f=new File("D:/test/abcd.txt");
try {
// 创建基本的文件输入流
FileInputStream fis =new FileInputStream(f);
// 创建字节数组
byte[] b=new byte[(int)f.length()];
//以字节流的形式读取文件内容
fis.read(b);
for (byte c : b) {
System.out.println(c); //a对应的ASCII码表 97 97 97 97
}
fis.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
以字节流的形式向文件写入数据
OutputStream是字节输出流,同时也是抽象类,只提供方法声明,不提供方法的具体实现。
FileOutputStream 是OutputStream子类,以FileOutputStream 为例向文件写出数据
注: 如果文件D:/test/abcd.txt不存在,写出操作会自动创建该文件
public class IOTest {
public static void main(String[] args) throws IOException {
// 绝对路径 创建文件 内容 aaa
File f=new File("D:/test/abcd.txt");
// 准备输出的字节数组 88:X 89:Y
byte[] b={88,89};
FileOutputStream fos=new FileOutputStream(f);
fos.write(b); //会覆盖原来的内容
fos.close();
System.out.println("写入成功");
}
}
2.5 关闭流的方式
所有的流,无论是输入流还是输出流,使用完毕之后,都应该关闭。 如果不关闭,会产生对资源占用的浪费。 当量比较大的时候,会影响到业务的正常开展。
在finally中关闭
这是标准的关闭流的方式
1. 首先把流的引用声明在try的外面,如果声明在try里面,其作用域无法抵达finally.
2. 在finally关闭之前,要先判断该引用是否为空
3. 关闭的时候,需要再一次进行try catch处理
使用try()的方式
把流定义在try()里,try,catch或者finally结束的时候,会自动关闭
这种编写代码的方式叫做 try-with-resources, 这是从JDK7开始支持的技术
所有的流,都实现了一个接口叫做 AutoCloseable,任何类实现了这个接口,都可以在try()中进行实例化。 并且在try, catch, finally结束的时候自动关闭,回收相关资源。
2.6 字符流
使用字符流读取文件
public class IOTest {
public static void main(String[] args) throws IOException {
// 绝对路径 创建文件 内容 XY
File f=new File("D:/test/abcd.txt");
// 创建Reader
FileReader fr=new FileReader(f);
char[] c=new char[(int)f.length()];
fr.read(c);
for (char d : c) {
System.out.println(d); // X Y
}
System.out.println("读入成功");
}
}
使用字符流把字符串写入到文件
FileWriter 是Writer的子类,以FileWriter 为例把字符串写入到文件
public class IOTest {
public static void main(String[] args) throws IOException {
// 绝对路径 创建文件 内容 XY
File f=new File("D:/test/abcd.txt");
// 创建 Writer
FileWriter fw=new FileWriter(f);
// 以字符流的形式把数据写入到文件中
String str="hello world !!!";
char[] c=str.toCharArray();
fw.write(c);
fw.close();
System.out.println("写入成功");
}
}
2.7 中文问题
常见编码
工作后经常接触的编码方式有如下几种:
ISO-8859-1 ASCII 数字和西欧字母
GBK GB2312 BIG5 中文
UNICODE (统一码,万国码)
其中
ISO-8859-1 包含 ASCII
GB2312 是简体中文,BIG5是繁体中文,GBK同时包含简体和繁体以及日文。
UNICODE 包括了所有的文字,无论中文,英文,藏文,法文,世界所有的文字都包含其中
如果完全按照UNICODE的方式来存储数据,就会有很大的浪费。
比如在ISO-8859-1中,a 字符对应的数字是0x61
而UNICODE中对应的数字是 0x00000061,倘若一篇文章大部分都是英文字母,那么按照UNICODE的方式进行数据保存就会消耗很多空间
在这种情况下,就出现了UNICODE的各种减肥子编码, 比如UTF-8对数字和字母就使用一个字节,而对汉字就使用3个字节,从而达到了减肥还能保证健康的效果
UTF-8,UTF-16和UTF-32 针对不同类型的数据有不同的减肥效果,一般说来UTF-8是比较常用的方式
Java采用的是Unicode
2.8 缓存流
字节流和字符流的弊端:
在每一次读写的时候,都会访问硬盘。 如果读写的频率比较高的时候,其性能表现不佳。
为了解决以上弊端,采用缓存流。
缓存流在读取的时候,会一次性读较多的数据到缓存中,以后每一次的读取,都是在缓存中访问,直到缓存中的数据读取完毕,再到硬盘中读取。
缓存流在写入数据的时候,会先把数据写入到缓存区,直到缓存区达到一定的量,才把这些数据,一起写入到硬盘中去。按照这种操作模式,就不会像字节流,字符流那样每写一个字节都访问硬盘,从而减少了IO操作
使用缓存流读取数据
缓存字符输入流 BufferedReader 可以一次读取一行数据
public class IOTest {
public static void main(String[] args) throws IOException {
// 绝对路径 创建文件 内容 hello world!!! 12306
File f=new File("D:/test/abcd.txt");
// 创建文件字符流
FileReader fr=new FileReader(f);
BufferedReader br=new BufferedReader(fr);
while(true){
// 一次读取一行
String line=br.readLine();
if(null==line)
break;
System.out.println(line);
}
System.out.println("读取成功");
}
}
使用缓存流写出数据
PrintWriter 缓存字符输出流, 可以一次写出一行数据
public class IOTest {
public static void main(String[] args){
// 绝对路径 创建文件 内容 hello world!!! 12306
File f=new File("D:/test/abcd.txt");
// 创建文件字符流
try (
// 创建文件字符流
FileWriter fw = new FileWriter(f);
// 缓存流必须建立在一个存在的流的基础上
PrintWriter pw = new PrintWriter(fw);
) {
pw.println("garen kill teemo");
pw.println("teemo revive after 1 minutes");
pw.println("teemo try to garen, but killed again");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Flush
有的时候,需要立即把数据写入到硬盘,而不是等缓存满了才写出去。 这时候就需要用到flush
2.9 数据流
DataInputStream 数据输入流
DataOutputStream 数据输出流
2.10 对象流
对象流指的是可以直接把一个对象以流的形式传输给其他的介质,比如硬盘
一个对象以流的形式进行传输,叫做序列化。 该对象所对应的类,必须是实现Serializable接口
2.11 System.in
System.out 是常用的在控制台输出数据的
System.in 可以从控制台输入数据
public class IOTest {
public static void main(String[] args) throws IOException{
InputStream is=System.in;
while (true) {
/**敲入a,然后敲回车可以看到
97 13 10
97是a的ASCII码
13 10分别对应回车换行
*/
int i=is.read();
System.out.println(i);
}
}
}
Scanner读取字符串
使用System.in.read虽然可以读取数据,但是很不方便
使用Scanner就可以逐行读取了
public class IOTest {
public static void main(String[] args){
System.out.println("请输入:");
Scanner sc=new Scanner(System.in);
String line=sc.nextLine();
System.out.println(line);
}
}