文章目录
1. java.io.File类
1.1 File类概述
1.java.io.File类的对象可以表示文件和目录
2.当我们有一个File对象的时候我们可以利用它来操作文件或者目录的属性。
3.但是File对象是不可以对文件进行读/写操作。
1.2 构造方法和方法
这里的路径可以包括绝对路径和相对路径。
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
File file11 = new File("F:/read.txt");// '/'左斜杠只需要一个
File file12 = new File("F:\\read.txt"); // '\'右斜杠需要两个 因为转义
File file2 = new File("1.txt"); //相对路径是在项目根目录下的
System.out.println("文件是否存在"+file11.exists());
System.out.println("是文件吗"+file11.isFile());
System.out.println("是目录吗"+file11.isDirectory());
System.out.println("名称:"+file11.getName());
System.out.println("绝对路径"+file11.getAbsolutePath());
System.out.println("文件大小"+file11.length());
} catch (Exception e) {
// TODO: handle exception
}
}
除了这些方法外,还有delete()删除文件,list()列出所有文件,endwith()根据文件名过滤,mkdirs()创建文件,creatNewFile()创建文件
流分为输入流和输出流
输入流:从外存读取数据到内存,输出流:将数据从内存写到外存中
输入输出流又根据传输格式的不同,分为字节流和字符流
字节流是指8位的通用字节流,以字节为基本单位,在java.io包中,对于字节流进行操作的类大部分继承于InputStream(输入字节流)类和OutputStream(输出字节流)类
字符流是指16位的Unicode字符流,以字符(两个字节)为基本单位,非常适合处理字符串和文本,对于字符流进行操作的类大部分继承于Reader(读取流)类和Writer(写入流)类
下面我们就一 一道来。
2.字节流(OutputStream类和InputStream类)
2.1 OutputStream类
介绍一下字节输出流OutputStream类
我们主要是使用write()方法,下面着重介绍一下该方法
第一个参数是选定byte数组b,第二个参数是用来选定从byte数组b的第几个字节开始加载,第三个参数表示写入的字节数量。以下用代码解释一下。
public static void main(String[] args) {
try {
//由于OutPutSteam是抽象类,所以我们使用它的实现类类FileOutPutSteam来实现
OutputStream os = new FileOutputStream("readme.txt");
//创建一个byte[]数组
byte[] bs = new String("123456").getBytes();
//整个bs数组写入
os.write(bs, 0, bs.length);
os.write('\n');
//从bs数组的第3(从0开始)个开始写入,写length-2个字节
os.write(bs, 2, bs.length-2);
os.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
以上代码实现了将byte[]数组写入文件的功能
2.2 InputStream类
我们最常用的是其read()方法。下面重点介绍一下
下面是一个简单使用read()方法的例子
public static void main(String[] args) {
try {
//由于OutPutSteam是抽象类,所以我们使用它的实现类类FileOutPutSteam来实现
InputStream os = new FileInputStream("readme.txt");
//创建一个byte[]数组
byte[] bs =new byte[10];
int len=0;
//read方法返回读到的字节数,并将数据存储到bs数组中
while((len=os.read(bs, 0, bs.length))!=-1){
//创建String str用来输出bs数组的内容
String str = new String(bs,0,len);
System.out.println(str);
}
os.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
3.字节流其他的子类
3.1 DataOutputStream类和DataInputStream
用这个类包装后,可以使用readInt()、readUTF()等方法,可以直接读取具体类型的数据(基本数据类型和String类型)
DataOutputStream 是用来装饰其它输出流,它实现了DataOutput接口,将DataOutputStream和DataInputStream输入流配合使用,允许应用程序以与机器无关方式从底层输入流中读写基本 Java 数据类型和字符串
以下是例子
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
OutputStream os = new FileOutputStream(new File("practice2"));
//用DataOutputStream类来修饰,可以使用writeInt() writeDouble() writeUTF()方法
DataOutputStream dos = new DataOutputStream(os);
dos.writeInt(10);
dos.writeDouble(1.1);
dos.writeUTF("abc");
dos.close();
os.close();
//读取同理
InputStream is =new FileInputStream(new File("practice2"));
DataInputStream dis = new DataInputStream(is);
System.out.println(dis.readInt());
System.out.println(dis.readDouble());
System.out.println(dis.readUTF());
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
3.2 BufferedOutputStream类和BufferedInputStream类
BufferedOutputStream的作用就是为输出流提供缓冲功能
在使用OutputStream和DataOutputStream的时候我们发现,就算是不使用close()和flush()方法,也可以写入文件。这是因为这些是不带缓冲的操作,每读一个字节就要写入一个字节,由于涉及磁盘的IO操作相比内存的操作要慢很多,所以不带缓冲的流效率很低。
带缓冲的流,可以一次读很多字节,但不向磁盘中写入,只是先放到内存里。等凑够了缓冲区大小的时候一次性写入磁盘,这种方式可以减少磁盘操作次数,速度就会提高很多!所以这就是为什么我们需要使用Buffered流。——参考https://blog.youkuaiyun.com/zhaoyanjun6/article/details/54894451
以下是使用的例子
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
OutputStream os = new FileOutputStream(new File("practice3"));
BufferedOutputStream bos = new BufferedOutputStream(os);
byte[] bs1 = new String("abcdefg").getBytes();
bos.write(bs1, 0, bs1.length);
//如果不关闭或者刷新 是不可以的
bos.close();
os.close();
InputStream is =new FileInputStream(new File("practice3"));
BufferedInputStream bis = new BufferedInputStream(is);
byte[] bs2 = new byte[3];
int len=0;
while((len = bis.read(bs2, 0, bs2.length))!=-1){
System.out.println(new String(bs2, 0, len));
}
bis.close();
is.close();
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
3.字符流(Reader类和Writer类)
FileInputStram类和FileOutputStream类虽然可以高效率地读/写文件,但对于Unicode编码的文件,我们需要自行将读取到的字节数据根据编码规则还原为字符串,因此使用它们有可能出现乱码
例子
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
FileWriter fw = new FileWriter(new File("practice4"));
BufferedWriter bfw = new BufferedWriter(fw);
bfw.write("可以使用buffered包装\n");
bfw.write("这样效率比较高");
bfw.close();
fw.close();
FileReader fr = new FileReader(new File("practice4"));
BufferedReader bfr = new BufferedReader(fr);
String str=null;
while((str=bfr.readLine())!=null){
System.out.println(str);
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
4.常见字节输出流工具
4.1 ByteArrayOutpuStream/ByteArrayInputStream类
ByteArrayOutputStream提供工具将内存中以串行序列存在的流式数据以一个字节为单位进行切分,形成一个byte[]数组
而ByteArrayInputStream则正好相反,提供工具将内存中的byte[]数组中的数据进行串行序列化拼接,形成一个可供操作的流式数据
public static void main(String[] args) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dots = new DataOutputStream(baos);
dots.writeUTF("我先存在baos中");
byte[] bs = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(bs);
DataInputStream dits = new DataInputStream(bais);
System.out.println(dits.readUTF());
} catch (Exception e) {
e.printStackTrace();
}
}
4.2PushbackInputStream类
缓存的新应用之一就是回推的实现。回推用于输入流,以允许读取字节,然后再将它们返回(回推)到流中,PushbackInputStream类实现了这一思想,提供了一种机制,可以“偷窥”来自输入流的内容而不对它们进行破坏
public static void main(String[] args) {
try {
ByteArrayInputStream bais = new ByteArrayInputStream(new String("1234567").getBytes());
PushbackInputStream pis = new PushbackInputStream(bais);
int len=0;
int b;
char c;
while((b=pis.read())!=-1){
c = (char)b;
System.out.println(c);
if(c=='2')
pis.unread('a');
}
} catch (Exception e) {
e.printStackTrace();
}
}
5. 对象序列化
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存持久化指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的"状态",即它的成员变量。由此可知,对象序列化不会关注类中的静态变量
除了在持久化对象时会用到对象序列化之外,在网络中传递对象时,也会用到对象序列化。Java序列化API为处理对象序列化提供了一个标准机制
在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化
java.io.Serializable是一个标识接口,即意味着它仅仅是为了说明类的可序列化属性,接口没有包含任何需要子类实现的抽象方法
接下来我们使用ObjectOutputStream.writeObject(Serializable obj)方法来序列化对象
以及ObjectInputStream.readObject来完成反序列化
class Person implements Serializable{
private String name;
private int age;
public Person() {
// TODO Auto-generated constructor stub
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
public class TestObjectSteam {
public static void main(String[] args) {
try {
//为了将序列化的内容存储到数组中,所以我们使用ByteArray类
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
Person p1 = new Person("小宋", 22);
oos.writeObject(p1);
byte[] bs = baos.toByteArray();
//这里打印了一下序列化的内容,发现是看不懂的。。
System.out.println(new String(bs));
ByteArrayInputStream bais= new ByteArrayInputStream(bs);
ObjectInputStream ois = new ObjectInputStream(bais);
Person p2 = (Person)ois.readObject();
System.out.println(p2);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
6. nio
NIO和IO之间最大的区别是:IO是面向流的,NIO是面向块(缓冲区)的
Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性
Java NIO中的Buffer用于和NIO通道进行交互。数据是从通道读入缓冲区,从缓冲区写入到通道中的
缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("4.txt");
FileOutputStream fos = new FileOutputStream("5.txt");
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel();
inChannel.transferTo(0, inChannel.size(), outChannel);
inChannel.close();
outChannel.close();
fos.close();
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
}