第一部分:InputStream & OutputStream
/ *
字符流:FileReader FileWriter
BufferedReaderBufferedWriter
LineNumberReader
|
|
| (字符数组char[]参数都变成字节数组byte[])
\V/
字节流:InputStream OutputStream
BufferedInputStream Buffered OutputStream
【练习】通过缓冲区演示MP3的复制。并显示拷贝时间
* /
import java.io.*;
class CopyMP3Demo
{
public static voidmain(String[] args){
long start =System.currentTimeMillis();//记录起始时间
copyMP3_2();
long end =System.currentTimeMillis();//记录结束时间
System.out.println("copy time :: " +(end-start)+"ms");
}
public static voidcopyMP3_2(){
MyBufferedInputStream mbis = null;
BufferedOutputStreambos = null;
try{
mbis =new MyBufferedInputStream(new FileInputStream(
"G:\\原点.mp3"));
bos = newBufferedOutputStream(new FileOutputStream("G:\\原点2.mp3"));
//byte[] pic = new byte[1024];
int num=0;
while((num = mbis.myRead())!=-1){
bos.write(num);
//bos.flush();
//犯错笔记:不需要刷新,因为缓冲区满或者关闭流的时候会自动写入。刷新时间开销巨大。
}
}
catch(IOException e){
throw newRuntimeException("Failed");
}
finally{
try{
if(bos!=null)
bos.close();
}
catch(IOException e){
throw new RuntimeException("WriteFailed");
}
finally{
try{
if(mbis!=null)
mbis.myClose();
}
catch (IOException e){
throw newRuntimeException("ReadFailed");
}
}
}
}
public static voidcopyMP3_1(){
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try{
bis = newBufferedInputStream(new FileInputStream(
"G:\\原点.mp3"));
bos = newBufferedOutputStream(new FileOutputStream("G:\\原点2.mp3"));
int num=0;
while((num = bis.read())!=-1){
bos.write(num);
//bos.flush();
}
}
catch(IOException e){
throw newRuntimeException("Failed");
}
finally{
try{
if(bos!=null)
bos.close();
}
catch(IOException e){
throw new RuntimeException("WriteFailed");
}
finally{
try{
if(bis!=null)
bis.close();
}
catch (IOException e){
throw newRuntimeException("ReadFailed");
}
}
}
}
}
class MyBufferedInputStream//自定义MyBufferedInputStream类
{
private InputStream in;
private int counter =0, pos = 0;
private byte[] buff =new byte[1024*4];
MyBufferedInputStream(InputStream in){
this.in = in;
}
public int myRead()throws IOException{
if (counter ==0){
counter =in.read(buff);
if(counter<0)
return -1;
pos=0;
byte b = buff[pos];
counter--;
pos++;
returnb&0xff;
}
else if(counter>0){
byte b =buff[pos];
counter--;
pos++;
returnb&0xff;
}
return -1;
}
public void myClose()throws IOException{
in.close();
}
}
/ *
!!!自定义MyBufferedInputStream类中myRead()方法时:
byte: -1 ---> int:-1
0000-0000 0000-0000 0000-0000 1111-1111
return int 时强转成:
1111-1111 1111-1111 1111-1111 1111-1111
转换后仍然是int型的-1,此时判断条件不满足无法读取继续写入,造成写入失败。
只要保留后1字节,前面3个字节取零即可,方法:对应数值&0xff(255)。
这时转成:
0000-0000 0000-0000 0000-0000 1111-1111
* // *
第二部分:转换流与流操作总结
InputStreamReader & OutputStreamWriter
【需求】:通过键盘录入数据,当录入一行数据后就将该行数据进行打印。
如果录入的数据是over则停止录入。
* // *
import java.io.*;
class IODemo3
{
public static voidmain(String[] args) throws IOException
{
InputStream in =System.in;
StringBuilder sb= new StringBuilder();
while (true)
{
int ch =in.read();
if(ch=='\r')
continue;
if(ch=='\n'){
if("over".equals(sb.toString()))
break;
else{
System.out.println(sb.toString());
sb.delete(0,sb.length());
}
}
else
sb.append((char)ch);
}
}
}
* // *
BufferedReader类中有readLine()方法,
键盘录入的read方法是字节流InputStream的方法。
【问题】如何将字节流转成字符流,再加以使用字符流缓冲区的readLine方法?
【InputStreamReader】是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。
它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。
构造函数:
InputStreamReader(InputStream in)
创建一个使用默认字符集的InputStreamReader。
【OutputStreamWriter】是字符流通向字节流的桥梁:可使用指定的 charset 将要写入流中的字符编码成字节。
它使用的字符集可以由名称指定或显式给定,否则将接受平台默认的字符集。
构造函数:
OutputStreamWriter(OutputStream out)
创建使用默认字符编码的OutputStreamWriter。
* // *
import java.io.*;
class IODemo3
{
public static voidmain(String[] args) throws IOException
{
InputStream in = System.in;
//InputStreamReader将字节流InputStream转换成字符流
BufferedReaderbr = new BufferedReader(new InputStreamReader(in));
OutputStream out= System.out;
BufferedWriter bw= new BufferedWriter(new OutputStreamWriter(out));
String line;
while((line =br.readLine())!=null){
if(line.equals("over"))
break;
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
}
}
* // *
1.源:键盘录入 目的:控制台
2.源:键盘录入 目的:文件
3.源:文件 目的:控制台
流操作的基本规律(四个明确):
1.明确操作的源和目的。
源:输入流 InputStream Reader
目的:输出流 OutputStream Writer
2.操作的数据是否是纯文本。
是:字符流。
不是:字节流。
3.通过两个明确判断要使用的体系,再明确要使用的具体对象,
通过设备乱来区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台
4.明确是否需要提高效率
【示例】:
1.【拷贝文本文件】
源:InputStream Reader
文本文件:Reader
设备:硬盘
Reader体系中操作文件的对象FileReader
目的:OutputStream Writer
文本文件:Writer
设备:硬盘
Writer体系中操作文件的对象FileWriter
需要提高效率?BufferedReader/BufferedWriter
2.【键盘录入数据保存到文件中】
源:(文本)Reader(字符流)
设备:键盘。对应对象System.in(字节流)
【转换】:InputStreamReader(System.in) 字节-->字符
效率:BufferedReader
目的:(文本)Writer
设备:硬盘。文本文件。使用FileWriter
效率:BufferedWriter
【扩展】:
需要把录入的数据按照指定编码表<utf-8>,将数据存入文件中
目的:(文本)Writer
设备:硬盘。文本文件。使用FileWriter
效率:BufferedWriter
但是存储时需要加入指定编码表。而编码表只有转换流对象可以指定。
因此需要OutputStreamWriter
BudderedWriter bw = newBufferedWriter(
newOutputStreamWriter(new FileOutpurStream("d.txt"),"UTF-8"));
【总结】:
涉及到字符编码转换时,需要使用转换流。
【扩展】:System类中设置标准输入输出流
System.setIn(InputStream in)
System.setOut(PrintStream p)
Ex: System.setIn(new FileInputStream("abc.txt"));
System.setOut(newPrintStream("qq.txt"));
【将异常信息写入日志】
* // *
import java.io.*;
import java.util.*;
import java.text.*;
class IODemo3
{
public static voidmain(String[] args) throws IOException
{
try{
int[] arr= new int[2];
System.out.println(arr[3]);
}
catch (Exceptione){
try{
Date d =new Date();
SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
String str = sdf.format(d);
PrintStream ps = newPrintStream("Exceptions.log");
ps.println(str);
System.setOut(ps);
}
catch(IOException ioe){
thrownew RuntimeException("LogBuiledFailed");
}
e.printStackTrace(System.out);
}
}
}
* // *
【打印系统属性信息】:
* /
import java.io.*;
import java.util.*;
class IODemo3
{
public static voidmain(String[] args) throws Exception
{
Properties props= System.getProperties();
PrintStream ps =new PrintStream("SystemProperties.txt");
props.list(ps);
}
}
/ *
File类:
【练习】:使用list方法列出某目录下的所有特定后缀名(如txt)的文件。
* // *
import java.io.*;
class FileDemo
{
public static void main(String[] args){
File dir = newFile("F:\\我的文档\\Music\\新歌");
String[] names =dir.list(new FilenameFilter(){
publicboolean accept(File dir,String name){
return name.endsWith(".txt");
}
});
for(Stringname:names){
System.out.println(name);
}
}
}
* // *
--------------------------------------
【练习】:列出某个目录下的所有层级内容,并写入文件中
* // *
import java.io.*;
class FileDemo
{
public static void main(String[]args) throws IOException{
File file = newFile("F:\\Courseware\\JAVA");
FileWriter fw =new FileWriter("G:\\Catalog.txt");
printLevel(file,0,"G:\\Catalog.txt");
}
public static StringgetLevelEx(int level){ //写入txt文件
StringBuilder sb= new StringBuilder();
sb.append("|---");
for (int i =0;i<level ;i++ )
{
sb.insert(0,"| ");
}
returnsb.toString();
}
public static voidprintLevel(File dir, int level,String str) throws IOException{
BufferedWriterfw = new BufferedWriter(new FileWriter(str,true));
fw.write(getLevelEx(level)+dir.getName());
fw.newLine();
fw.flush();
level++;
File[] files=dir.listFiles();
for (intl=0;l<files.length ;l++ )
{
if(files[l].isDirectory())
printLevel(files[l],level,str);//递归调用
else{
fw.write(getLevelEx(level)+files[l].getName());
fw.newLine();
}
}
fw.close();
}
}
【注意】:可以考虑使用集合装入特定目录下的文件与文件夹,然后再取出文件,获得路径,最后写入文本文件中。
* // *
--------------------------------------------------------------------------------------------------
【删除一个带内容的目录】:
删除原理:
在windows中,删除目录是从里面往外面删除的。
既然是层次的,就可以利用递归调用。
* // *
import java.io.*;
class FileDemo
{
public static voidmain(String[] args) throws Exception{
File dir = newFile("F:\\Courseware\\JAVA\\file");
removeDir(dir);
}
public static void removeDir(Filedir){
File[] files =dir.listFiles();
for(File f :files){
if((!f.isHidden()) && f.isDirectory()){ //避开隐藏文件
removeDir(f);
}
else{
System.out.println(f.toString()+"------FILE------"+f.delete());
}
}
System.out.println(dir.toString()+"::::::DIR::::::"+dir.delete());
dir.delete();
}
}
* // *
--------------------------------------------------------------------------------------------------
【练习】:将练习目录下的java文件列成清单写入txt文件中
* /
import java.util.*;
import java.io.*;
class FileDemo
{
public static voidmain(String[] args){
File dir = newFile("F:\\Courseware\\JAVA");
List<File>list = new ArrayList<File>();
fileToList(dir,list);
writeToText(list,newFile(dir,"java_list.txt"),"java");
}
//先把指定目录dir下的文件或文件夹装入集合list中
public static voidfileToList(File dir,List<File> list){
File[] files =dir.listFiles();
for(File f:files){
if(f.isDirectory())
fileToList(f,list);
else{
list.add(f);
}
}
}
//list集合作为容器装在指定文件,desFile参数为目的文件,type为保留文件的后缀名
public static voidwriteToText(List<File> list,File desFile,String type){
BufferedWriterbw =null;
try{
bw = newBufferedWriter(new FileWriter(
desFile.toString()));
Iterator<File> it = list.iterator();
while(it.hasNext())
{
File f = it.next();
if(f.getName().endsWith("."+type)){
bw.write(f.getAbsolutePath().toString());
bw.newLine();
bw.flush();
}
}
}
catch(IOException e){
throw newRuntimeException("WriterFailed");
}
finally{
if(bw!=null){
try{bw.close();}
catch (IOException e){
throw new RuntimeException("CloseFailed");}
}
}
}
}