java语言基础入门——各类流的介绍

1、什么是流?流是一个抽象的概念,代表一串数据集合,当java程序需要从数据源读取数据时,就开启了一个到数据源的流,同样,当数据需要输出数据到达目的地时,也需要开启一个流。流是用来处理数据的通道。流有字节流,字符流;输入流,输出流。

2、InputStream和OutputStream是以字节为单位的输入输出抽象流类(输入是指从字节到流(可读),输出是指从流到字节(可写))。

3、Reader和Writer是以字符为单位的输入、输出抽象流类(输入是指从字节到流(可读),输出是指从流到字节(可写))

4、FileInputStream和FileOutputStream是以字节为操作单位的文件输入流和文件输出流。FileReader和FileWriter是以字符为操作单位的文件输入流和文件输出流。一般来讲,以字节为单位的适合用来对图片、声音、视频等文件进行操作。而已字符为单位的适合对文本文件进行操作。

使用I/O流类来操作对象时一般步骤如下:

(1)创建连接到指定数据源的I/O流对象

(2)利用I/O流类提供的方法进行数据的读取和写入,整个过程中都需要操作java.io.IOException异常。另外,如果是向输入流写入数据,还需要在写入操作完成后调用flush()方法强制写出所有缓冲的数据。

(3)操作完毕后,一定要调用close()方法关闭I/O流对象,后创建的先关闭。

package stream;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class FileRWTest {

	public static void main(String[] args) {
		try {
			/**
			 * 使用以字节为单位的可以有效减少乱码产生
			 */
			FileReader fileReader=new FileReader("test1.txt");
			FileWriter fileWriter=new FileWriter("test_new.txt");
			char charArray[]=new char[20];
			int length=0;
			while((length=fileReader.read(charArray))!=-1){
				fileWriter.write(charArray,0,length);
			}
			fileWriter.flush();
			System.out.println("复制完成");
			fileReader.close();
			fileWriter.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

package stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import commonly_class.string;

public class FileStreamTest {


/**
 * US-ASCII Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set 
ISO-8859-1   ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1 
UTF-8 Eight-bit UCS Transformation Format 
UTF-16BE Sixteen-bit UCS Transformation Format, big-endian byte order 
UTF-16LE Sixteen-bit UCS Transformation Format, little-endian byte order 
UTF-16 Sixteen-bit UCS Transformation Format, byte order identified by an optional byte-order mark 

 * @param args
 */
	public static void main(String[] args) {
		try {
			FileInputStream fileInputStream=new FileInputStream("tset.mp4");
			FileOutputStream fileOutputStream=new FileOutputStream("test_new.mp4");
		    byte byteArray[]=new byte[21];//使用字节流读取数据,容易出现乱码
		    int length=0;
		    while ((length=fileInputStream.read(byteArray))!=-1) {//在文件结尾处返回-1
		    	fileOutputStream.write(byteArray,0,length);//用length控制复制范围,防止在最后一次多复制
				//String string=new String(byteArray,0,length);
				//System.out.println(string);
		    }
		    fileOutputStream.flush();//刷新数据流
		    System.out.println("复制完成");
		    fileInputStream.close();//关闭
		    fileOutputStream.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		

	}

}


5、缓冲流:为了提高读写速度,java提供了缓冲功能的流类,在使用这些带缓冲功能的流类时,它会创建一个内部缓存冲区数组。在读取字节或字符时,会先从数据源取到数据填充到缓冲区,然后在返回。在写入字节和字符时,会先以写入的数据填充到该内部缓冲区,然后依次性将目标写入数据源中。简而言之就是在数据源(磁盘)和流之间建立一个区域,用于一次性取较多数据并缓存起来,流再从该区域取数据,这样就减少访问数据源次数,提高效率。

缓冲流也分为两类,针对字节的缓冲输入和输出流:BufferedInputStream和BufferedOutputStream;针对字符的缓冲输入流和输出流:BufferedReader和BufferedWriter

package stream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

public class BufferedIOTest {

	public static void main(String[] args) {
		/**
		 * 使用缓冲区处理大型文件可以提高很大的效率
		 * 具体什么时候能达到效率最高,
		 * 需要反复调试BufferedOutputStream(fileOutputStream,50000);和new byte[3000];的数值匹配
		 */
		try {
			FileInputStream fileInputStream=new FileInputStream("tset.mp4");
			FileOutputStream fileOutputStream=new FileOutputStream("test_new.mp4");
			BufferedInputStream bufferedInputStream=new BufferedInputStream(fileInputStream,50000);
			BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(fileOutputStream,50000);
		    byte byteArray[]=new byte[3000];//使用字节流读取数据,容易出现乱码
		    int length=0;
		    while ((length=bufferedInputStream.read(byteArray))!=-1) {
				bufferedOutputStream.write(byteArray, 0, length);
			}
		    System.out.println("复制成功");
		    bufferedOutputStream.flush();//刷新缓冲区
		    bufferedInputStream.close();//依次关闭流
		    bufferedOutputStream.close();
		    fileInputStream.close();
		    fileOutputStream.close();
		} 
		
		catch (FileNotFoundException e) {
				e.printStackTrace();
		    } catch (IOException e) {
			e.printStackTrace();
		    }

	}

}


6、转换流用于字节流和字符流之间的转换。InputStreamReader用于将字节流读取的字节按指定字符集解码成字符,他需要与InputStream套接。OutputStreamWriter用于将写入到字节流的字符按照指定字符集编码成字节,它需要与OutputStream套接。

package stream;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class ByteToChar {

	public static void main(String[] args) {
		System.out.println("请输入信息(退出输入e)");
		//将在标准的输入流的字节流转化为字符流,再包装成缓冲流
		BufferedReader bufferedReader=new BufferedReader(
				new InputStreamReader(System.in));
		String string=null;
		try {
			while ((string=bufferedReader.readLine())!=null) {
				if (string.equalsIgnoreCase("e")) {//输入e退出
					System.out.println("安全退出!");
					break;
				}
				System.out.println("---->:"+string.toUpperCase());//将字符串转化为大写
				System.out.println("请继续输入信息");
				
			}
			bufferedReader.close();//关闭缓冲流,会自动关闭它包装的底层的字节流和字符流
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}


7、数据流是用来专门把Double、Int等基本数据类型写入文本或从文本中读取数据。数据流主要有两类,DataInputStream和DataOutputStream,分别用来读取和写入基本数据类型的数据。,例如他们分别对应readInt()方法和writeBoolean()分别代表读取一个int类型数据和写入一个Boolean类型数据。

package stream;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;

public class TestDataStream {

	public static void main(String[] args) {
		ByteArrayOutputStream baos=new ByteArrayOutputStream();
		DataOutputStream dos=new DataOutputStream(baos);//数据流
		try {
			dos.writeInt(1);
			dos.writeBoolean(true);
			dos.writeChars("中国china\t");
			dos.writeUTF("中国china");
			ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
			System.out.println(bais.available());//长度
			DataInputStream dis=new DataInputStream(bais);
			System.out.println(dis.readInt());//读取一个32为整数
			System.out.println(dis.readBoolean());
			char temp[]=new char[200];
			int length=0;
			char c=0;
			while ((c=dis.readChar())!='\t'){
				temp[length]=c;
				length++;
			}
			String string=new String(temp,0,length);
			System.out.println(string);
			System.out.println(dis.readUTF());//读取一个由UTF格式字符组成的字符串
			dos.close();
			dis.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}


8、打印流,PrintStream和PrintWriter流都属于打印流,他们提供了一系列的print和println方法,可以实现将基本数据类型的数据格式转化为字符串输出。我们常用的Systeam.out.println语句中的Systeam.out就是PrintStream类的一个实例

package stream;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;

import javax.crypto.NullCipher;
/**
 * 把标准的输出改为文件的输出
 * @author kepu
 *
 */
public class PrintStreamTest {

	public static void main(String[] args) {
		FileOutputStream fos=null;
		try {
			fos=new FileOutputStream("test1.txt");
			//创建打印输出流,设置为自动刷新模式
			PrintStream ps=new PrintStream(fos, true);
			if(ps!=null){
				//把标准输出流改为文件
				System.setOut(ps);
			}
			for (int i = 0; i <255; i++) {//输入ASCII字符
				System.out.print((char)i);
				if (i%50==0) {
					System.out.println();
				}
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		finally{
			try {
				fos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		

	}

}


9、对象流。JDk中提供了ObjectOutputStream和ObjectInputStream类是用于存储和读取基本数据类=类型数据或对象的流,他的强大之处在于可以把java中的对象写到数据源中,也能把对象中还原回来。用ObjectOutputStream类保存基本数据类型或对象的机制叫做序列化;用ObjectInputStream类读取基本数据类型或对象的机制叫做反序列化。

需要注意的是ObjectOutputStream和ObjectInputStream不能序列化static或transient修饰的成员变量。另外,能被序列化的对象所对应的类必须实现java.io.Serializable这个标示性接口。

package stream;

public class Student implements java.io.Serializable {

	/**
	 * 凡是实现 Serializable接口的类都有一个表示序列化版本的标识符
	 * erialVersionUID用来表示类的不同版本间的兼容性
	 * erialVersionUID可以显示的表示出来,也可以采用系统默认的值,
	 * 对代码进行修改再重新编译时,erialVersionUID的值可能会改变
	 * 显示的定义erialVersionUID的值主要有以下两种用途:
	 * 在某些场合,希望类的不同版本对序列化兼容,因此需要确保不同版本具有相同的erialVersionUID值
	 * 在某些场合,希望类的不同版本对序列化不兼容,因此需要确保不同版本具有不同的erialVersionUID值
	 */
	private static final long erialVersionUID = 858606830804257830L;
	private int id;
	private String name;
	private transient int age;//不需要序列化的属性
    public  Student(int id,String name ,int age) {
		this.age=age;
		this.id=id;
		this.name=name;
	}
	public int getId() {
		return id;
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	public String toString() {
		return "id:  "+id+"name:  "+name+"age:   "+age;
	}
}

package stream;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class ObjectIOStreamTest {

	public static void main(String[] args) {
		ObjectOutputStream oos=null;
		ObjectInputStream ois=null;
		try {
			//创建连接到指定文件的对象流实例
			oos=new ObjectOutputStream(new FileOutputStream("test1.txt"));
			ois=new ObjectInputStream(new FileInputStream("test1.txt"));
			oos.writeObject(new Student(22, "张三", 18));
			//把Student对象序列化到文件中
			oos.flush();//刷新输出流
			System.out.println("序列化成功");
			Student student=(Student) ois.readObject();//读取对象
			System.out.println(student);
			System.out.println("反序列化成功");
		} catch (FileNotFoundException e) {
			
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		finally{
			try {
				oos.close();
				ois.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		

	}

}


10、ZIP文件流,由于网络宽带速度有限,所以数据文件的压缩有利于数据在Internet上快速传输,同时也节省空间。java实现了I/O数据流与网络数据流的单一接口,因此数据的压缩、网络传输和解压文件的实现比较容易。java支持GIZP和ZIP两种格式。以ZIP为例来讲,主要有java.util.zip包中ZipEntry、ZipInputStream、ZipoutputStream三个类实现ZIP数据压缩方法的实现。

ZipEntry代表ZIP文件条目,要压缩的文件都要转化为一个个条目

ZipInputStream实现了ZIP压缩文件的读输入流,支持压缩和非压缩entry

ZipOutputStrem实现了ZIP压缩文件的输出流,支持压缩和非压缩entry

package stream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

public class ZipOutDemo {

	public static void main(String[] args) {
		/**
		 * 对单一文件压缩
		 */
		ZipOutputStream zos=null;
		FileInputStream fis=null;
		BufferedInputStream bis=null;
		BufferedOutputStream bos=null;
		ZipEntry ze=null;//条目
		String tarstr = "tset.mp4";//源文件
		String destrtr = "zzz.zip";//目标文件
		try {
			//创建文件输入流对象
			fis = new FileInputStream(tarstr);
			//创建Zip输出流
			zos=new ZipOutputStream(new FileOutputStream(destrtr));
			//创建条目
			ze=new ZipEntry(tarstr);
			//写入条目
			zos.putNextEntry(ze);
			//创建输出输入缓冲流
			bos=new BufferedOutputStream(zos,10000);
			bis=new BufferedInputStream(fis,10000);
			
			//byte c=0;
			byte b[]=new byte[500];
			int c=0;
			while ((c= bis.read(b))!=-1) {
				bos.write(b,0,c);
			}
			bos.flush();//刷新zip输出流
			zos.closeEntry();//关闭当前zip条目
			System.out.println("压缩完成");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		finally{
			try {
				fis.close();//关闭各种流
				zos.close();
				bis.close();
				bos.close();
			} catch (IOException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
		}
		/**
		 * 对单一文件解压
		 */
		ZipInputStream zis=null;
		FileOutputStream fos=null;
		ZipEntry ze2=null;
		String tarstr2 = "zzz.zip";//源文件
		String destsr2 = "zzz.mp4";//目标文件
		try {
			//创建文件输出流对象
			fos=new FileOutputStream(destsr2);	
			//创建zip输入流
			zis=new ZipInputStream(new FileInputStream(tarstr2));
			//写入条目
			ze2=zis.getNextEntry();
			//创建输出输入缓冲流
			bos=new BufferedOutputStream(fos,10000);
			bis=new BufferedInputStream(zis,10000);		
			byte b[]=new byte[500];
			int c=0;
			while ((c= bis.read(b))!=-1) {//边读边写
				fos.write(b,0,c);
			}
			zis.closeEntry();//关闭当前zip条目
			System.out.println("解压完成");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		finally{
			try {
				bis.close();//关闭各种流
				bos.close();
				fos.close();
				zis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
	}

}

package stream;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

import try_catch.ThrowsDemo;
/**
 *  zip压缩文件夹与解压文件夹
 * @author kepu
 *
 */
public class ZipTest {

	public static void main(String[] args) {
		zipFile("g:\\www", "g:\\abc.zip");
		System.out.println("压缩完成");
		upZipFile("g:\\abc.zip","g:\\www_new");
		System.out.println("解压完成");

	}
	//zip压缩功能。压缩baseDir(文件目录下)的所有文件,包含子目录
	public static void zipFile(String baseDir,String fileName) {
		List<File> fileList =getSubFiles(new File(baseDir));
		ZipOutputStream zos =null;//zip输出流
		ZipEntry ze=null;//条目
		byte buf[]=new byte[1000];//缓冲区
		try {
			zos = new ZipOutputStream(new FileOutputStream(fileName));
			for(File f: fileList){
				//条目的名只能使用相对于基目录的相对路径
				ze = new ZipEntry(getAbsFileName(baseDir, f));
				//文件当做条目使用
				ze.setSize(f.length());
				ze.setTime(f.lastModified());
				zos.putNextEntry(ze);//开始一个新文件写入
				InputStream is = new BufferedInputStream(new FileInputStream(f));
				//创建连接到指定文件的输入流
				int readLen=-1;
				while((readLen=is.read(buf))!=-1){//从文件中读取数据
					zos.write(buf, 0, readLen);//往ZIp输出流中写
				}
				zos.closeEntry();//关闭当前条目
				is.close();
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			try {
				zos.close();
			} catch (IOException e) {			
				e.printStackTrace();
			}
		}
	}
//给定根目录,返回另一个文件名的相对路径,使用ZIP文件的路径
	public static String getAbsFileName(String baseDir,File file)throws IOException{
		String reult=file.getName();//记住文件名
		File base=new File(baseDir);
		File temp=file;
		while (true) {
			temp=temp.getParentFile();
			if((temp==null)||(temp.equals(base))){
				break;
			}else {
				reult=temp.getName()+"/"+reult;
			}
		}
		reult=base.getName()+"/"+reult;
		return reult;
		
	}
	//递归获取指定目录下的所有子孙文件、目录列表
	private static List<File> getSubFiles(File baseDir) {
		List<File> list =new ArrayList<File>();
		File tmp[]=baseDir.listFiles();
		for (int i = 0; i < tmp.length; i++) {
			if (tmp[i].isFile()) {
				list.add(tmp[i]);
			}
			if (tmp[i].isDirectory()) {
				list.addAll(getSubFiles(tmp[i]));//递归
			}
		}
		return list;
	}

	/**
	 * 解压缩功能. 将zipName文件解压到destDir目录下.
	 */
	@SuppressWarnings("unchecked")
	public static void upZipFile(String zipName, String destDir) {
		ZipFile zfile = null;
		ZipEntry ze = null;
		byte[] buf = new byte[8192];
		
		try{
			zfile = new ZipFile(zipName);
			Enumeration zList = zfile.entries();
			while (zList.hasMoreElements()) { //遍历zip中的条目
				ze = (ZipEntry) zList.nextElement();
				if (ze.isDirectory()) {  //如果条目是目录
					File f = new File(destDir + "/" + ze.getName());
					f.mkdir();
				}else{
					OutputStream os = new BufferedOutputStream(
											new FileOutputStream(
												getRealFileName(destDir, ze.getName())));
					
					InputStream is = new BufferedInputStream(zfile.getInputStream(ze));
					
					int readLen = -1;
					while ((readLen = is.read(buf)) != -1) {
						os.write(buf, 0, readLen);
					}
					
					is.close();
					os.close();
				}
				
			}
		}catch(IOException e){
			e.printStackTrace();
		}finally{
			try {
				zfile.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 给定根目录,返回一个相对路径所对应的实际文件名.
	 * @param baseDir 指定根目录
	 * @param absFileName 相对路径名,来自于ZipEntry中的name
	 * @return java.io.File 实际的文件
	 */
	public static File getRealFileName(String baseDir, String absFileName) {
		String[] dirs = absFileName.split("/");
		File dest = new File(baseDir);
		if (dirs.length > 1) {
			for (int i = 0; i < dirs.length - 1; i++) {
				dest = new File(dest, dirs[i]);
			}
			if (!dest.exists()){
				dest.mkdirs();
			}
			dest = new File(dest, dirs[dirs.length - 1]);
			return dest;
		}
		return dest;
	}
}


11、随机存储流类,RandomAccessFile是一个特殊的流类,它可以在文件的任何地方读取或写入数据。打开一个随机存储文件后,要么对他进行只读操作,要么同时进行读写操作。可以通过他的构造方法的第二个参数进行设置,r为只读。rw为读写,还要rws,rwd。

随机存取文件的类似于存储文件系统中的一个大型的byte数组,它提供了一个指向该数组的光标或索引,成为文件指针,该文件指针用来标识将要进行的读写操作的下一个字节位置,getFilePointer方法可以返回文件指针的当前位置。使用seek方法可以将文件指针移动到该文件内部的任意字节位置处。

package stream;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

public class RandomAccessFileTest {

	public static void main(String[] args) {
		File file = new File("g:"+File.separator+"test.txt");
		try {
			RandomAccessFile raf=new RandomAccessFile(file, "rw");
			//同时读写方式,文件如果不存在,会创建文件
			String name = null;
			int age=0;
			name="dds   sh";//字符串长度为8
			age=22;//数字长度为4
			raf.writeBytes(name);//写字符串
			raf.writeInt(age);//写整型
			name="dddd    ";//字符串长度为8
			age=10;//数字长度4
			raf.writeUTF(name);//写字符串
			raf.writeInt(age);//写整型
			name="lilidqqqq";//字符串长度8
			age=19;//数字长度4
			raf.writeUTF(name);//写字符串
			raf.writeInt(age);//写整型
			
			System.out.println("写入完成");
			byte b[]=new byte[8];
			
			raf.seek(0);
			//raf.skipBytes(12);
			for (int i = 0; i <b.length; i++) {
				b[i]=raf.readByte();
				
			}
			name=new String(b);
			age=raf.readInt();
			System.out.println("第一个学员信息为: name:+"+name+ "   age:"+age);
			raf.seek(12);
			//raf.skipBytes(12);
			name=raf.readUTF();
			age=raf.readInt();
			System.out.println("第二个学员信息为: name:+"+name+ "   age:"+age);
			raf.close();
		} catch (FileNotFoundException e) {
			
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}
另外,在Apache提供的各类库中有更为丰富的类和接口,使用起来也很方便。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值