流的概念:
流是java语言中用来处理输入输出的方式。采用流的方式,使得开发人员可以方便的对不同的数据进行处理和保存数据。
流的分类:
流
|--字节流
|--输入流:InputStream是抽象类,是所有字节输入流的父类。
|--输出流:OutputStream是抽象类,是所有字节输出流的父类。
|--字符流
|--输入流:Reader是抽象类,是读取字符流的父类。
|--输出流:Writer是抽象类,是字符输出流的父类。
字节流的读入和写出:
package StreamDemo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class StreamDemo {
public static void main(String[] args) {
streamDemo_1();
}
public static void streamDemo_1(){
FileInputStream fileIn = null;
FileOutputStream fileOut = null;
try {
fileIn = new FileInputStream("test1.txt"); //通过打开一个到实际文件的连接来创建一个 FileInputStream,
//该文件通过文件系统中的路径名 name 指定。
fileOut = new FileOutputStream("test2.txt");//如果该目录下不存在test1.txt,则会创建test1.txt
//如果该目录下存在test1.txt,则会覆盖原来的test1.txt
//read()方法每次读取返回一个字节,为什么不用byte接受而用int?
/*因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制的的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
* 那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上
* 24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
*/
int num=0;
try {
while((num=fileIn.read())!=-1){ //将每次读到的字节赋给num,当读到没有时返回的是-1. read方法每读一次就向后移动一次
fileOut.write(num);
fileOut.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
finally{
try {
if (fileIn!=null) {
fileIn.close(); //关闭流释放资源
}
} catch (Exception e2) {
e2.printStackTrace();
}
try {
if (fileOut!=null) {
fileOut.close(); //关闭流释放资源
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
flush和close方法的区别
public class DemoFlush {
public static void main(String[] args) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(""));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(""));
int b;
while((b = bis.read()) != -1){
bos.write(b);
// bos.flush(); //需要实时刷新缓冲区内容时使用flush
} //
bis.close();
bos.close();/* flush和close的区别
* flush刷新之后还可以继续写
* close在关闭之前会刷新一次,把缓冲区剩余的字节刷到文件上去,但是调用之后不能再写
*/
}
}
字符流的读入和写出:
package StreamDemo;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class StreamDemo {
public static void main(String[] args) {
streamDemo_2();
}
public static void streamDemo_2(){
FileReader fr = null;
FileWriter fw = null;
/*拷贝纯文本的文件用字符流好还是用字节流好?
* 拷贝纯文本字节流更好,因为字符流也是用字节的形式进行操作先将字节转化为字符然后再将字符转化为字节输出浪费时间。而字节流是直接将字节传入传出
*
* 字符流在什么时候用呢?
* 操作纯文本
* 只读,一次读取的是一个字符,不会出现乱码
* 只写,可以直接写出的是字符串,不用转换
*
* 当字符流拷贝非纯文本文件和拷贝纯文本的操作是一样的,需要先将字节转换为字符,转换字符如果没有转换成功就会变成?,写出去的时候
* 就会将?写出,也就是会乱码
*
* 字符流只能操作纯文本的文件
* 字节流可以操作的是任意文件*/
try {
fr = new FileReader("test1.txt");
fw = new FileWriter("test2.txt");
int num = 0;
while((num=fr.read())!=-1){
fw.write(num);
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
try {
if (fr!=null) {
fr.close(); //关闭流释放资源
}
} catch (Exception e2) {
e2.printStackTrace();
}
try {
if (fw!=null) {
fw.close(); //关闭流释放资源
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
复制文件的四种方式:
public class DemoCopy {
public static void main(String[] args) throws IOException {
<strong>copy1();</strong>//逐个字节拷贝:效率太慢
<strong>copy2();</strong>//将整个文件转化为一个字节数组拷贝:文件太大的话可能造成内存溢出
<strong>copy3();</strong>//定义一个小数组拷贝文件:推荐使用
<strong>copy4();</strong>//使用缓冲区拷贝:推荐使用
//3和4相比差不多,相比之下3比4快一点点,因为在缓冲区内是一个字节一个字节传给输出流的
}
private static void <strong>copy4()</strong> throws FileNotFoundException, IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("logo.jpg"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
int b;
while((b = bis.read()) != -1){/*如果文件足够大,read()方法执行一次,就会将文件上字节数据一次读取8192个字节存储在BufferedInputStream的缓冲区中
从缓冲区中返给一个字节一个字节返给b
如果write一次,先将缓冲区装满,然后一次性的写到文件上去
这么做减少了到硬盘上读和写的操作*/
bos.write(b);
}
bis.close();
bos.close();
}
private static void<strong> copy3(</strong>) throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("logo.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg");
int len; //声明变量用来记录读取字节个数
byte[] arr = new byte[1024*8];
while((len =fis.read(arr)) != -1){ //如果read方法忘记写字节数组了,就会返回的字节的码表值,写出就会比原来的文件大的多
fos.write(arr, 0, len);
}
fis.close();
fos.close();
}
private static void <strong>copy2()</strong> throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("logo.jpg");
FileOutputStream fos = new FileOutputStream("copy.jpg");
byte[] arr = new byte[fis.available()];//根据文件大小做一个字节数组
fis.read(arr); //将文件上的所有字节读取到数组中
fos.write(arr); //将数组中的所有字节一次写到了文件上
fis.close();
fos.close();
}
private static void <strong>copy1()</strong> throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("E:\\logo.jpg");//创建输入流对象,并关联E:\\logo.jpg
FileOutputStream fos = new FileOutputStream("logo.jpg");//创建输出流对象,并关联logo.jpg
int b; //声明一个变量
while((b = fis.read()) != -1){ //变量接受写入的每个字节,并判断结果是否为-1
fos.write(b); //将变量接收 的每个字节写入
}
fis.close(); //关闭输入流
fos.close(); //关闭输出流
}
}
装饰设计模式:
装饰设计模式解决:对一组类进行功能的增强。
包装:写一个类(包装类)对被包装对象进行包装;
* 1、包装类和被包装对象要实现同样的接口;
* 2、包装类要持有一个被包装对象;
* 3、包装类在实现接口时,大部分方法是靠调用被包装对象来实现的,对于需要修改的方法我们自己实现。
BufferedReader的readLine()方法和newLine()方法
/** BufferedReader的readLine()方法可以读取一行字符(不包含换行符号)
* BufferedWriter的newLine()可以输出一个跨平台的换行符号"\r\n"
* @param args
* 将一个文本文档上的文本反转,第一行和倒数第一行交换,第二行和倒数第二行交换
* @throws IOException
*/
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("test1.txt"));//创建输入流并关联文件test1.txt
ArrayList<String> list = new ArrayList<>(); //创建集合
String line;
while((line = br.readLine()) != null){ //按行读取文件
list.add(line); //将读取的每行文件放集合中
}
br.close(); //关闭流 流对象晚开早关
BufferedWriter bw = new BufferedWriter(new FileWriter("test2.txt"));//创建输出流对象并关联test2.txt,这里写同样的名字不会删除文件内容
//因为都在缓冲区中
for (int i = list.size()-1; i >= 0; i--) { //倒序遍历
bw.write(list.get(i)); //将遍历内容写入文件中
bw.newLine(); //换行 这种方式 跨平台,\r\n只用于windows
}
bw.close(); //关闭流
}
LineNumberReader
package StreamDemo;
import java.io.FileReader;
import java.io.LineNumberReader;
public class LineNumberReaderDemo {
/*
* LineNumberReader是BufferedReader的子类, 具有相同的功能, 并且可以统计行号
* 调用getLineNumber()方法可以获取当前行号
* 调用setLineNumber()方法可以设置当前行号
*/
public static void main(String[] args) {
lineNumberReaderDemo();
}
public static void lineNumberReaderDemo(){
LineNumberReader lnr = null;
try {
lnr = new LineNumberReader(new FileReader("test3.txt"));
String line = null;
//lnr.setLineNumber(100);
while((line=lnr.readLine())!=null){
System.out.println(lnr.getLineNumber()+"……"+line);
}
} catch (Exception e) {
e.printStackTrace();
}
finally{
try {
if(lnr!=null){
lnr.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
转换流
package StreamDemo;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
public class InputStreamRaderDemo {
public static void main(String[] args) {
//inputStreamRaderDemo();
outputStreamWriterDemo();
}
public static void inputStreamRaderDemo(){
BufferedReader bufr = null;
try {
bufr = new BufferedReader(new InputStreamReader(System.in)); //InputStreamReader 是字节流通向字符流的桥梁
String line = null;
while((line=bufr.readLine())!=null){
if(line.equals("over"))
break;
System.out.println(line.toUpperCase());
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void outputStreamWriterDemo(){
BufferedWriter bufw = null;
BufferedReader bufr = null;
try {
//OutputStreamWriter 是字符流通向字节流的桥梁
bufw = new BufferedWriter(new OutputStreamWriter(System.out));
bufr = new BufferedReader(new InputStreamReader(new FileInputStream("BufferedDemo.java")));
String line = null;
while((line = bufr.readLine())!=null){
bufw.write(line);
bufw.newLine();
}
System.out.println("复制完成!");
} catch (Exception e) {
e.printStackTrace();
}
finally{
try {
if(bufr!=null){
bufr.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
try {
if(bufw!=null){
bufw.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
}
标准输入输出流
/*System.in 标准输入流 返回值是InputStream 默认可以从键盘输入读取字节数据
* System.out 标准输出流 返回是PrintStream 默认可以向Console中输出字符和字节数据 */
public static void main(String[] args) throws IOException {
System.setIn(new FileInputStream("logo.jpg"));//修改标准输入流
System.setOut(new PrintStream("copy.jpg"));//修改标准输出流
InputStream is = System.in; //获取标准输入流对象
OutputStream os = System.out; //获取标准输出流对象
int b;
byte[] arr = new byte[8192];//定义小数组提高效率
while((b = is.read(arr)) != -1){
os.write(arr,0,b);
}
is.close();
os.close();
}
}
序列流
/*.什么是序列流
* 序列流可以把多个字节输入流整合成一个, 从序列流中读取数据时, 将从被整合的第一个流开始读, 读完一个之后继续读第二个, 以此类推.*/
public static void main(String[] args) throws IOException {
//demo1();
//序列流整合多个文件
FileInputStream fis1 = new FileInputStream("test1.txt");//创建输入流对象并关联文件test1.txt
FileInputStream fis2 = new FileInputStream("test2.txt");//创建第二个输入流对象并关联文件test2.txt
FileInputStream fis3 = new FileInputStream("test3.txt");//创建输入流对象并关联文件test3.txt
FileInputStream fis4 = new FileInputStream("test4.txt");//创建第二个输入流对象并关联文件test4.txt
Vector<FileInputStream> v = new Vector<>();//创建vactor集合对象
v.add(fis1); //添加流对象
v.add(fis2);
v.add(fis3);
v.add(fis4);
Enumeration<FileInputStream> en = v.elements();//调用枚举
SequenceInputStream sis = new SequenceInputStream(en);//传给序列流
FileOutputStream fos = new FileOutputStream("test5.txt");//创建输出流,并关联test5.txt
int b;
while ((b = sis.read()) != -1){
fos.write(b);
}
sis.close();
fos.close();
}
private static void demo1() throws FileNotFoundException, IOException {
//序列流整合两个文件,
FileInputStream fis1 = new FileInputStream("test1.txt");//创建输入流对象并关联文件test1.txt
FileInputStream fis2 = new FileInputStream("test2.txt");//创建第二个输入流对象并关联文件test2.txt
SequenceInputStream sis = new SequenceInputStream(fis1,fis2);//创建序列流对象并关联两个文件
FileOutputStream fos = new FileOutputStream("test6.txt");//创建输出流对象并关联test6.txt
int b ;
while((b = sis.read()) != -1){
fos.write(b);
}
sis.close();
fos.close();
}
}