OutputSream
这个类实现了Closeable和Flushable接口,这两个接口都只有一个方法,分别是关闭流,刷新流;OutputStream常用的实现子类:FileOutputStream(文件输出流),下面给出FileOutputStream常用的方法:
①构造方法,常用的构造有FileOutputStream(File file)
,FileOutputStream(String fileName)
,FileOutputStream(FIle file,boolean append)
,FileOutputStream(String fileName,boolean append);
也就是说构造参数可以传文件名也可是一个文件对象,第二个参数的含义为:是否是追加到文件末尾,默认是false,也就是如果不设置为true的话,会覆盖掉原来的文件信息。设置为true则不会覆盖,只是追加到末尾。
②写方法
write(int b)
只写入一个字节,写入b的低8位
write(byte[] b)
这个是以字节为单位写入的
write(byte[] b,int off,int len)
后两个参数的含义是起始位置和要输出的长度,常用。
③关闭和刷新
close()
一般使用完之后都手动关闭,不关闭的话也会提交,因为没有使用到缓冲区,而下面的Writer是必须要close或者flush才能提交的,因为缓冲区不满是不会自动提交的。
flush()
刷新流,刷新之后会提交数据,一般在Writer中才会用。
给出一个简单的写程序:
import java.io.*;
public class OutputStreamTest01 {
public static void main(String args[]) throws IOException {
File file = new File("D:" + File.separator + "TestJavaFile" + File.separator + "file2.txt");
OutputStream outputStream = new FileOutputStream(file,true);
outputStream.write("哈哈哈哈\r\n".getBytes());
outputStream.write(1024);
outputStream.close();
}
}
InputStream
这个类常用的子类为FileInputStream,它的常用方法如下:
①构造方法,同OutputStream类似,只是不需要第二个参数,因为是输入,没有追加的说法;
②读方法
int read()
这个方法每次只读一个字节的数据,返回读到的这个字节,初学者可能会有疑问,如果不是数字那读到什么,其实是数字也不是读到数字本身,因为文件是以二进制存储的,每次读到的实际上是它对应的ascll码值,比如如果文件里面有个1,读到的应该是49;如果是字母也是读到对应的ascll码,如果是汉字,一个汉字两个字节也就是16位,那么一个汉字需要读2次,每次读到汉字的二进制前8位,所以读到的是什么就没必要纠结了。
int read(byte[] b)
这个方法是一次读取的数据取决于b数组的大小,如果文件里面有足够多的数据,那么可以读满,返回值自然是读到的字节个数,如果文件数据不够多了,读不满这个数组,那么返回值是实际读到的大小。这个是最常用的方法。
int read(byte[] b,int off,int len)
这个方法返回的是每次读取到的长度,off和len表示从文件读len的数据从b数组的off位置开始存。
以上的读方法都是返回值为-1表示读取完了,下面给出一个简单的读文件程序:
import java.io.*;
public class InputStreamTest01 {
public static void main(String args[]) throws IOException {
File file=new File("D:" + File.separator + "TestJavaFile" + File.separator + "file3.txt");
InputStream inputStream=new FileInputStream(file);
byte data[]=new byte[1024];
int len=0;
while (len!=-1) {
len = inputStream.read(data);
System.out.println(len);
System.out.println(new String(data));
}
}
}
运行结果:
Writer
Writer只是一个抽象类,常用的子类有FileWriter,与OutputStream实现的功能类似,使用的方法也基本一致,其优点就是,直接针对字符操作,在java中char类型是占2个字节的,所以可以直接对中文字符直接操作,OutputStream是对单个字节进行处理,有可能某次只取到半个汉字,Writer就不会出现这样的情况,另外,它还不仅局限于字节数组,还可以直接输出字符串类型,Writer常用的的方法还有append(String s)直接追加字符串输出。
但是需要注意的是:FileWriter并不是Writer的直接子类,而是OutputStreamWriter的直接子类,OutputStreamWriter才是Writer的直接子类,OutputStreamWrite叫做转换流,它以OutputStream作为构造参数获得OuputStream对象,而OutputStream又与File的对象有关联,从而Writer才可以直接以File作为构造参数从而间接获得OutputStreamWrite对象。所以啊,Writer的实现并不是直接就是从文件拿到字符,而是利用到了字节流OutputStream,在中间多加了一个缓冲区,然后每次从缓冲区成对成对地取字节(也就是说字节都是成对被取走),使得每次返回的数据是以字符的形式存在。
Reader
常用FileReader子类,继承关系与Wtiter的类似,用法与InputStream类似,读入的是数据以字节为单位,不能像Writer那样可以直接操作字符串,而是以字符数组作为参数接收读入的数据。返回值是读到的字符数。
ByteArrayInputStream和ByteArrayOutputStream
这两个是内存流,input是用于向一块内存写入数据,output是存放读到的数据,这与文件流是不同的。这两个类分别是InputStream和OutputStream的子类;同时Writer和Reader也有相应的子类,用于以字符为单位的读取。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ByteArrayStreamTest {
public static void main(String args[]) throws IOException {
String str="哈哈哈哈哈1111111111111111111111111111111111111111111111111111111111111111";
ByteArrayInputStream inputStream=new ByteArrayInputStream(str.getBytes()); //为内存空间开辟一个’读‘的流
ByteArrayOutputStream outputStream=new ByteArrayOutputStream(33);
int b=0;
while((b=inputStream.read())!=-1) { //读取内存的数据
outputStream.write(b); //这里读取到的b会写到outpuStream中,这与文件流是不同的,这个输出流的的容量会自动扩增
}
System.out.println(outputStream);
}
}
面试题-拷贝目录
import java.io.*;
public class CopyDir {
static private String src1;
static private String des2;
public static void main(String args[]) throws IOException {
CopyDir copyDir = new CopyDir("D:" + File.separator + "TestJavaFile", "D:" + File.separator + "TestJavaFile2");
CopyDir.copyDir(new File(src1));
}
public CopyDir(String src1, String des2) {
this.src1 = src1;
this.des2 = des2;
}
/**
*
* @param d1 需要复制的目录
* @return
* @throws IOException
*/
static boolean copyDir(File d1) throws IOException {
/**
* 如果是目录那么需要递归,不是目录就进行调用下面的文件复制方法来复制
* 复制与被复制的目录(文件)后半段路径是相同的,源目录中文件的前半段为源目录src1,被复制到的目录前半段为复制目录des2
* 所以只需要将前面不同的路径替换即可得到被复制到的文件路径
*/
if (d1.isDirectory()) {
File subFile[] = d1.listFiles();
for (int i = 0; i < subFile.length; i++) {
copyDir(subFile[i]);
}
}else {
String newFilePath = d1.getPath().replace(src1, des2);
File newFile = new File(newFilePath);
copyFile(d1, newFile);
}
return true;
}
/**
*
* @param f1 需要复制的文件
* @param f2 复制到的那个文件
* @return
* @throws IOException
*/
static boolean copyFile(File f1, File f2) throws IOException {
if (!f1.exists()) {
return false;
}
if (!f2.getParentFile().exists()) {
f2.getParentFile().mkdirs();
}
InputStream inputStream = new FileInputStream(f1);
OutputStream outputStream = new FileOutputStream(f2);
byte[] data = new byte[1024];
while (inputStream.read(data) != -1) {
outputStream.write(data);
}
return true;
}
}