java中的IO流可以按照不同的角度来分类:
1、按流的方向不同可以分为:输入流、输出流
2、按流的数据单位不同可以分为:字符流、字节流
3、按流的功能可以不同可以分为:节点流、处理流
字符流:Reader、Writer两大抽象类,所以要通过子类去实现他们的功能。该流是处理字符数据的。如文字。
FileReader类:该类的功能的读取一个文件的字符。如下程序:注:要想使下面程序能成功运行要在e盘下建立一个1.txt的文件。因为FileReader在构造时要接收一个文件
import java.io.*;
public class FileWriterTest{
public static void main(String[] args) throws IOException {
FileReader frd=new FileReader("e:\\1.txt");
int len=-1;
while((len=frd.read())!=-1){
System.out.print((char)len);
}
frd.close();
}
}
上面程序是先将一个文件字符输入流与文件相关联,从文件中每次读取一个字符并将字符打印处理,如果读到文件末尾将等于-1跳出循环。在跳出循环后关闭与之相关的系统资源。
FilerWriter类:该类的功能是将字符写入到某个文件中。
import java.io.*;
public class FileWriterTest{
public static void main(String[] args) throws IOException {
FileWriter frd=new FileWriter("e:\\1.txt");
frd.write("abc");
//frd.flush();
frd.close();
}
}
上面程序执行后如果e盘下有该文件那么将字符写入到该文件中(覆盖),如果没有该文件,那么将在该盘下创建该文件并将字符写如到文件中。从程序中可以看到frd.flush()方法这个方法的作用就是将流中的数据刷新到文件中,如果没有该方法和frd.close()方法,那么字符将会在流中没有写入到文件中。如果没有frd.flush()方法有frd.close()方法,那么程序在执行frd,close()方法时在关闭系统资源前自动将流中的数据刷新到文件中。
字节流:InputReader、OutputWriter两大抽象类,也是所有输入、输出流的超类。该流是专门处理字节数据的(也可以处理字符数据。前提是要将字符数据转化为字节数据)。如图片
下面通过FileInputStream和FileOutputstrean两个类来实现一张图片从e盘下复制到c盘下。程序如下:
import java.io.*;
public class DemoTest{
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("e:\\1.jpg");
FileOutputStream fos=new FileOutputStream("c:\\1.jpg");
byte[] buf=new byte[1024];
while((fis.read(buf))!=-1){
fos.write(buf,0,buf.length);
}
fis.close();
fos.close();
}
}
前面程序中可以看到每次读取字符都是一个字符一个字符的读,是不是速度慢,感觉很不爽?那么下面说一说带有缓冲区的字符输入输出流BufferedReader、BufferedWriter
通过查阅API文档可以看到BufferedReader类中有一个读一行的方法。下面通过程序来看看这个类该怎么用。
程序功能实现一个记事本文件从e盘复制到c盘。
import java.io.*;
public class BufTest{
public static void main(String[] args) throws IOException {
BufferedReader br=new BufferedReader(new FileReader("e:\\1.txt"));
BufferedWriter bw=new BufferedWriter(new FileWriter("c:\\1.txt"));
String line=null;
while((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
从上面程序可以看出在读取文件的时候是每次都是读取一行的,写入文件的时候也是将一行一行的将数据写入到文件中。在写入文件后面都加一个换行符(方法newLine()),这是BuuferedWriter的特点。
如果在控制台中输入字母,将这些字母写入到文件中,程序该如何写呢?
先来分析下:读取控制台数据可以用System.in,写入到文件中可以用FileWriter类,为了提高效率可以用BufferedReader、BufferedWriter进行包装。而Ststem.in是字节读取流,BufferedReader是字符输入流,那该怎么办?我们可以在中间环节加入一个转换流。如下程序:
import java.io.*;
public class BufTest{
public static void main(String[] args) throws IOException {
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw=new BufferedWriter(new FileWriter("e:\\1.txt"));
String line=null;
while((line=br.readLine())!=null){
if(line.equals("over")){
break;
}
bw.write(line);
bw.newLine();
}
br.close();
bw.close();
}
}
上面通过在控制台中输入over来结束程序,并将数据写入到了文件中。而新出现的类InputStreamReader是字符流通向字节流的桥梁。
通过上面所见可以总结出流操作的基本规律:
流操作的基本规律
1:明确源和目的
源:输入流 inputstream Reader
目的:输出流 outputstream Writer
2:操作的数据是否是纯文本
是:字符流
不是:字节流
3:当体系明确后,在明确要使用哪个具体的对象
通过设备来进行区分
源设备:内存,硬盘、键盘
目的设备:内存 、硬盘、控制台
File类:
先来看一看File类怎么创建创建文件
import java.io.*;
public class FileTest{
public static void main(String[] args) throws IOException {
File file=new File("e:\\b\\1.txt");
file.createNewFile();
}
}
从实验的结果可以发现,当该目录下如果有文件将不创建文件,如果没有文件将会创建。
import java.io.*;
public class FileTest{
public static void main(String[] args) throws IOException {
File file=new File("e:\\b\\3.txt");
System.out.println(file.delete());
}
}
如果目录下没有3.txt打印false,所以当要删除某个文件时应该先判断文件是否存在,如果存在才将文件删除。程序如下:
import java.io.*;
public class FileTest {
public static void main(String[] args) throws IOException {
File file = new File("e:\\b\\1.txt");
if (file.isFile()) {
System.out.println("文件存在删除:" + file.delete());
} else
System.out.println("文件不存在创建:"+file.createNewFile());
}
}
下面通过File类和输出流功能遍历出某一个盘符的所有文件,并将路径文件写入到一个记事本中。
import java.io.*;
import java.util.*;
public class FileTest {
public static void main(String[] args) throws IOException {
File file = new File("e:\\");
BufferedWriter br=new BufferedWriter(new FileWriter("e:\\a\\6.txt"));
List<File> list=new ArrayList<File>(); //用集合将遍历到的文件存储起来
recursionTest(file,list); //遍历文件的方法
for(File ls:list){
br.write(ls.toString()); //将集合中的数据写入到记事本中
br.newLine(); //换行
}
br.close();
}
private static void recursionTest(File file,List list) {
File[] fls=file.listFiles(); 遍历该目录下的所有目录或文件
for(File fl:fls){
if(fl.exists()){
if(fl.isDirectory() && !fl.isHidden()){ //如果是目录且不是隐藏的那么继续递归遍历
recursionTest(fl,list);
}
else
if(fl.isFile()){ //如果是文件那么就将文件写入到list集合中
list.add(fl);
}
}
}
}
}
管道流:一个PipedInputStream对象和一个PipedOutputStream对象进行连接实现通信管道,就如同一根水管一样,从一端倒入水而从另一端流出水,这两个类主要用于线程之间的通信,一个线程写入管道流中一个线程取出管道流中的数据。
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class Test {
public static void main(String[] args) throws IOException {
PipedInputStream pis=new PipedInputStream();
PipedOutputStream pos=new PipedOutputStream();
pos.connect(pis);
new Thread(new PipedInputStreamTest(pis)).start();
new Thread(new PipedOutputStreamTest(pos)).start();
}
}
class PipedInputStreamTest implements Runnable{
private PipedInputStream in;
public PipedInputStreamTest(PipedInputStream in){
this.in=in;
}
@Override
public void run() {
byte[] buf=new byte[1024];
int len=-1;
try {
len=in.read(buf);
System.out.println(new String(buf,0,len));
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
class PipedOutputStreamTest implements Runnable{
private PipedOutputStream out;
public PipedOutputStreamTest(PipedOutputStream out){
this.out=out;
}
@Override
public void run() {
String str="guang dao liu";
try {
out.write(str.getBytes());
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
当一次读取多个文件怎么办?这时可以用SequenceInputStream类,这个类表示其他输入流的逻辑串联。
下面将多个文件中的内容写入到一个文件中。程序如下:
import java.io.*;
import java.util.*;
public class SequenceInputStreamTest {
public static void main(String[] args) throws IOException {
Vector<FileInputStream> v=new Vector<FileInputStream>(); //因为SequenceInputStream接收一个Enumeration所以定义一个Vector
BufferedWriter br=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("e:\\4.txt"))); //定义一个输出流与一个文件关联
v.add(new FileInputStream("e:\\1.txt"));
v.add(new FileInputStream("e:\\2.txt"));
v.add(new FileInputStream("e:\\3.txt"));
Enumeration<FileInputStream> en= v.elements(); //转换为Enumeration
SequenceInputStream sis=new SequenceInputStream(en);
int len=-1;
byte[] buf=new byte[1024]; //读取多个文件中的内容并将内容写入到一个指定的文件中
while((len=sis.read(buf,0,buf.length))!=-1){
br.write(new String(buf,0,len));
}
sis.close(); //关闭资源操作
br.close();
}
}
上面程序实现了文件合并功能,那么文件切割该怎么实现呢?
import java.io.*;
import java.util.*;
public class FileTest {
public static void main(String[] args) throws IOException {
FileInputStream fis=new FileInputStream("e:\\1.mp3");
FileOutputStream fos=null;
int len=-1;
byte[] buf=new byte[1024*1024];
int count=1;
while((len=fis.read(buf))!=-1){
fos=new FileOutputStream("c:\\"+(count++)+".suipian");
fos.write(buf,0,len);
}
fis.close();
fos.close();
}
}
ByteArrayInputStream和ByteArratOutputStream类:这两个类主要是操作字节数组的。假如需要创建一个临时文件,可以用这两个类在内存中创建一个虚拟临时文件,实现读取和写入操作。可以不用对硬盘进行操作所以速度快。
import java.io.*;
import java.util.*;
public class ByteArrayInputStreamTest{
public static void main(String[] args) throws IOException {
byte[] bt="lin shi xu ni wen jian".getBytes();
ByteArrayInputStream bis=new ByteArrayInputStream(bt); //创建字节数组输入流
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int len=-1;
while((len=bis.read())!=-1){ //读取输入流中的数据
bos.write(len); //将数据写入到字节数组输出流中
}
bis.close();
bos.close();
System.out.println(bos.toString()); //将流中的数据以字符串的形式打印出来。
}
}
RandomAccessFile类:这个一个很强大的类,它具有随机读取和写入操作的能力,直接继承Object类
import java.io.*;
import java.util.*;
public class FileTest {
public static void main(String[] args) throws IOException {
RandomAccessFile raf=new RandomAccessFile("e:\\1.txt","rw");
byte[] str="123456".getBytes();
raf.write(str);
raf.seek(3); //设置从哪里开始读取数据
byte[] buf=new byte[1024];
int len=0;
len=raf.read(buf);
System.out.println(new String(buf,0,len));
}
}
运行结果是:4 5 6
从程序可以看出写入的数据是1 2 3 4 5 6而打印出来的数据是4 5 6该程序说明了这个类具有随机访问性。
字符编码:
先看下面程序的结果:
import java.io.*;
public class FileTest {
public static void main(String[] args) throws IOException {
BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(new FileOutputStream("e:\\2.txt"),"utf-8"));
BufferedReader br=new BufferedReader(new InputStreamReader(new FileInputStream("e:\\2.txt"),"gbk"));
bw.write("张三");
bw.close();
String line=null;
while((line=br.readLine())!=null){
System.out.println(line);
}
}
}
程序是先写入张三两字到文件中,而运行后的结果是乱码?这是为什么呢?这是因为先将张三以UTF-8编码写入到文件中的,而取出的时候却用的是gbk编码。所以导致了乱码。
假如UTF-8编码87、76代表张三两字。在取出是的时候87 76在gbk编码中又代表了其他字,那么取出的汉字就不是张三。如下图所示