------
Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
IO流总结(一)
字符流和字节流:
字节流两个基类:
InputStream OutputStream
字符流两个基类:
Reader Writer
先学习一下字符流的特点。
既然IO流是用于操作数据的,
那么数据的最常见体现形式:文件。
那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter.后缀名是父类名,前缀名是该流对象的功能!
IO异常的处理方式。
字节流两个基类:
InputStream OutputStream
字符流两个基类:
Reader Writer
先学习一下字符流的特点。
既然IO流是用于操作数据的,
那么数据的最常见体现形式:文件。
那么先以操作文件为主来演示。
需求:在硬盘上,创建一个文件并写入一些文字数据。
找到一个专门用于操作文件的Writer子类对象。FileWriter.后缀名是父类名,前缀名是该流对象的功能!
<span style="font-size:14px;">import java.io.*;
class FileWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个FileWriter对象。该对象一杯初始化就必须要明确被操作的文件。
//而且该文件会被创建到指定的目录下。如果该目录下已有同名文件,将被覆盖。
//其实该步就是明确数据要存放的目的地。
FileWriter fw = new FileWriter("demo.txt");
//调用write方法,将字符串写入到流中。
fw.write("abcde");
//刷新流对象中的缓冲中数据。
//将数据刷到目的地。
//fw.flush();
//关闭流资源,但是关闭之前会刷新一次内部的缓冲中的数据。
//将数据刷到目的地。
//和flush去别:flush刷新后,刘可以继续使用,close刷新后,会将流关闭。
fw.close();
}
}</span>
IO异常的处理方式。
<span style="font-size:14px;">class FileWriterDemo2
{
public static void main(String[] args)
{
FileWriter fw = null;
try
{
fw = new FileWriter("k:\\demo.txt");
fw.write("abcde");
}
catch (IOException e )
{
System.out.println("catch:"+e.toString());
}
finally
{
try
{
if(fw!=null)
fw.close();
}
catch (IOException e )
{
System.out.println("catch:"+e.toString());
}
}
}
}</span>
演示对已有文件的数据续写
<span style="font-size:14px;">import java.io.*;
class FileWriterDemo3
{
public static void main(String[] args) throws IOException
{
//传递一个true参数,代表不覆盖已有的文件,并在已有文件的末尾处进行数据续写。
FileWriter fw = new FileWriter("demo.txt",true);
fw.write("haha\r\nxiexie");
fw.close();
}
}</span>
FileReader用法
import java.io.*;
class FileReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个文件读取流对象,和指定名称的文件相关联。
//要保证该文件是已经存在的,如果不存在,会发生异常FileNotFoundException
FileReader fr = new FileReader("demo.txt");
//调用读取流对象的read方法。
//read();一次读一个字符。而且会自动往下读。
int ch = 0;
while ((ch=fr.read())!=-1)
{
System.out.println("ch="+(char)ch);
}
/*
while(true)
{
int ch = fr.read();
if(ch==-1)
break;
System.out.println("ch="+(char)ch);
}
*/
fr.close();
}
}
字符流:
FileReader
FileWriter
BufferedReader
BufferedWriter
字节流:
INputStream OutPutStream
需求,想要操作图片数据。这时就要用到字节流。
读取一个.java文件,并打印在控制台上。
<span style="font-size:14px;">import java.io.*;
class FileReaderTest
{
public static void main(String[] args) throws IOException
{
FileReader fr = new FileReader("FileWriterDemo.java");
char[] buf = new char[1024];
int num = 0;
while ((num =fr.read(buf))!=-1 )
{
System.out.print(new String(buf,0,num));
}
fr.close();
}
}</span>
字符读取流缓冲区:
该缓冲区提供了一个一次读一行的方法 readLine()。方便于对文本数据的获取。
当返回null时,表示读到文件末尾。
readLine方法返回的时候只返回回车符之前的数据内容。并不返回回车符。
<span style="font-size:14px;">import java.io.*;
class BufferedReaderDemo
{
public static void main(String[] args) throws IOException
{
//创建一个读取流对象和文件关联。
FileReader fr = new FileReader("buf.txt");
//为了提高效率。加入缓冲技术。将字符读取流对象作为参数传递给缓冲对象的构造函数。
BufferedReader bufr = new BufferedReader(fr);
String line = null;
while ((line = bufr.readLine())!=null)
{
System.out.println(line);
}
bufr.close();
}
}</span>
缓冲去的出现时为了提高流的操作效率而出现的。
所以在创建缓冲区之前,必须要现有流对象。
该缓冲区中提供了一个跨平台的换行符。
<span style="font-size:14px;">import java.io.*;
class BufferedWriterDemo
{
public static void main(String[] args) throws IOException
{
//创建一个字符写入流对象。
FileWriter fw = new FileWriter("buf.txt");
//为了提高字符写入流效率,加入了缓冲技术。
//只要将需要被提高效率的流对象作为参数传递给缓冲去的构造函数即可。
BufferedWriter bufw = new BufferedWriter(fw);
for (int x = 1;x < 5 ;x++ )
{
bufw.write("abcde"+x);
bufw.newLine();
bufw.flush();
}
//记住,只要用到缓冲区,就要记得刷新。
//bufw.flush();
//其实关闭缓冲区,就是在关闭缓冲区中的流对象。
bufw.close();
}
}</span>
演示mp3的复制。通过缓冲区。
BufferedOutputStream
BufferedInputStream
<span style="font-size:14px;">import java.io.*;
class CopyMp3
{
public static void main(String[] args) throws IOException
{
long start = System.currentTimeMillis();
copy_1();
long end = System.currentTimeMillis();
System.out.println((end-start)+"毫秒");
}
public static void copy_1() throws IOException
{
BufferedOutputStream bufos = new BufferedOutputStream(new FileOutputStream("c:\\Copytext.mp3"));
BufferedInputStream bufis = new BufferedInputStream(new FileInputStream("c:\\0.mp3"));
int by = 0 ;
while ((by=bufis.read())!=-1)
{
bufos.write(by);
}
bufos.close();
bufis.close();
}
}</span>
复制一个图片
思路:
1,用字节读取流对象和图片关联。
2,用字节写入流对象创建一个图片文件。用于存储获取到的图片数据。
3,通过魂环读写,完成数据的存储。
4,关闭资源。
<span style="font-size:14px;">import java.io.*;
class CopyPic
{
public static void main(String[] args)
{
FileOutputStream fos = null;
FileInputStream fis = null;
try
{
fos = new FileOutputStream("c:\\Copy_text.jpg");
fis = new FileInputStream("c:\\psb.jpg");
byte[] buf = new byte[1024];
int len = 0;
while ((len=fis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
}
catch (IOException e )
{
throw new RuntimeException("复制文件失败");
}
finally
{
try
{
if(fis!=null)
fis.close();
}
catch (IOException e )
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(fos!=null)
fos.close();
}
catch (IOException e )
{
throw new RuntimeException("写入关闭失败");
}
}
}
}</span>
复制的原理:
其实就是将C盘下的文件数据存储到D盘的一个文件中。
步骤:
1,在D盘创建一个文件,用于存储C盘文件中的数据。
2,定义读取流和C盘文件关联。
3,通过不断的读写完成数据储存。
4,关闭资源。
<span style="font-size:14px;">import java.io.*;
class CopyText
{
public static void main(String[] args) throws IOException
{
Copy_2();
}
public static void Copy_2()
{
FileReader fr = null;
FileWriter fw = null;
try
{
fw = new FileWriter("C:\\Copy.txt");
fr = new FileReader("D:\\java0217\\day08\\FileWriterDemo.java");
char[] buf = new char[1024];
int len = 0;
while ((len=fr.read(buf))!=-1)
{
fw.write(buf,0,len);
}
}
catch (IOException e )
{
throw new RuntimeException("读写失败");
}
finally
{
if(fw!=null)
try
{
fw.close();
}
catch (IOException e)
{
}
if(fr!=null)
try
{
fr.close();
}
catch (IOException e)
{
}
}
}
//从C盘读一个字符,就往D盘写一个字符
public static void Copy_1() throws IOException
{
//创建目的地
FileWriter fw = new FileWriter("C:\\Copy.txt");
//与已有文件关联
FileReader fr = new FileReader("D:\\java0217\\day08\\FileWriterDemo.java");
int ch = 0;
while ((ch=fr.read())!=-1)
{
fw.write(ch);
}
fw.close();
fr.close();
}
}
</span>
通过缓冲区复制一个。java文件
<span style="font-size:14px;">import java.io.*;
class CopyTextByBuf
{
public static void main(String[] args)
{
BufferedReader bufr = null;
BufferedWriter bufw = null;
try
{
bufr = new BufferedReader(new FileReader("BufferedWriterDemo.java"));
bufw = new BufferedWriter(new FileWriter("bufWriter_Copy.txt"));
String line = null;
while ((line=bufr.readLine())!=null)
{
bufw.write(line);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw new RuntimeException("读写失败");
}
finally
{
try
{
if(bufr!=null)
bufr.close();
}
catch (IOException e)
{
throw new RuntimeException("读取关闭失败");
}
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
throw new RuntimeException("写入关闭失败");
}
}
}
}
</span>
|-- InputStreamReader
|--FileReader:专门踊跃处理文件的字符读取流对象。
Writer
|-- OutputStreamWriter
|--FileWriter:专门用于处理文件的字符写入流对象。
Reader中的常见方法:
1,int read():
读取一个字符。返回的是读到的那个字符。如果读到流的末尾,返回-1.
2,int read(char[ ])
将独岛的字符存入指定的数组中,返回的是读到的字符个数,也就是往数组里装的元素个数。
如果读到流的末尾,返回-1.
3,close():
读取字符其实用的是window系统的功能,就希望使用完毕后,经i系那个资源的释放。
Writer中的常见方法:
1,write(ch):将一个字符写入到流中。
2,write(char[]):将一个字符数组写入到流中。
3,write(String):将一个字符串写入到流中。
4,flush():刷新流,将流中的数据刷新到目的地中,流还存在。
5,close():关闭资源:在关闭钱会先调用flush(),刷新流中的数据去目的地。然后流关闭。
FileWriter:
该类没有特有的方法。只有自己的构造函数。
该类特点:
1,用于处理文本文件。
2,该类中有默认的编码表。
3,该类中有临时缓冲。
构造函数:在写入流对象初始化时,必须要有一个存储数据的目的地。
FileWriter(String filename):
该构造函数做了什么事情呢?
1,调用系统资源。
2,在指定位置,创建一个文件。
注意:如果该文件已存在,将会被覆盖。
FileWriter(String filename,boolean append):
构造函数 :当属按入的boolean类型值为true是,会在指定文件末尾处进行数据的续写。
FileReader:
1,用于读取文本文件的流对象。
2,用于关联文本文件。
构造函数:在读取流对象初始化的时候,必须要指定一个被读取的文件。
如果该文件不存在会发生FileNotFoundException.
PS:本段来自百度文库,毕老师总结。
File类常见方法:
1,创建。
boolean createNewFile();在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs();创建多级文件夹。
2,删除。
boolean delete();删除失败返回false。
void deleteOnExit();在程序退出是删除指定文件
1,创建。
boolean createNewFile();在指定位置创建文件,如果该文件已经存在,则不创建,返回false.
和输出流不一样,输出流对象一建立创建文件。而且文件已经存在,会覆盖。
boolean mkdir():创建文件夹。
boolean mkdirs();创建多级文件夹。
2,删除。
boolean delete();删除失败返回false。
void deleteOnExit();在程序退出是删除指定文件
3,判断。
boolean exists(): 文件是否存在。
isFile();是否是文件
ifDirectory();是否是文件夹
isHidden();是否是隐藏文件
isAbsolute();是否是绝对路径
4,获取信息。
getName()
getPath()
getParent()
getAbsolutePath()
lastModified()
length()
import java.io.*;
class FileDemo
{
public static void main(String[] args) throws IOException
{
method_4();
}
public static void method_1() throws IOException
{
File f = new File("file.txt");
//sop("create:"+f.createNewFile());
sop("delete:"+f.delete());
}
public static void method_2()
{
File f = new File("file.txt");
//sop("execute:"+f.canExecute());
//创建文件夹
File dir = new File("abc");
sop("mkdir:"+dir.mkdir());
}
public static void method_3()
{
File f = new File("file.txt");
//记住在判断文件对象是否是文件或者目录时,必须要先判断该文件对象封装的内容是否存在。
//通过exists判断。
sop("dir:"+f.isDirectory());
sop("file:"+f.isFile());
}
public static void method_4()
{
File f = new File("c:\\a.txt");
sop("path:"+f.getPath());
sop("abspath:"+f.getAbsolutePath());
sop("parent:"+f.getParent());//该方法返回的是绝对路径中的父目录!如果获取的是相对路径,返回null。
//如果相对路径中有上一层目录那么该目录就是返回结果
}
//创建File对象
public static void consMethod()
{
//将a.txt封装成file对象。可以将已有的和未出现的文件或者文件夹封装成对象。
//一下三种方式创建File对象。
File f1 = new File("a.txt");
File f2 = new File("c:\\abc","b.txt");
File d = new File("c:\\abc");
File f3 = new File(d,"c.txt");
sop("f1:"+f1);
sop("f2:"+f2);
sop("f3:"+f3);
File f4 = new File("c:"+File.separator+"abc\\zzz\\a.txt");//File.separator作为跨平台使用的目录分隔符。
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
打印出当前目录下所有文件包含隐藏文件
import java.io.*;
class FileDemo2
{
public static void main(String[] args)
{
File dir = new File("c:\\");
File[] files = dir.listFiles();
for(File f : files)
{
System.out.println(f.getName()+"::"+f.length());
}
}
public static void LiseDemo_2()
{
File dir = new File("d:\\java0217\\day08");
String[] arr = dir.list(new FilenameFilter()
{
public boolean accept(File dir,String name)
{
//System.out.println("dir:"+dir+"....name::"+name);
return name.endsWith(".txt");
}
});
System.out.println("len:"+arr.length);
for(String name : arr)
{
System.out.println(name);
}
}
public static void listDemo()
{
File f = new File("c:\\");
String[] names = f.list();//调用list方法的file对象不许是封装了一个目录。该目录还必须存在。
for (String name : names)
{
System.out.println(name);
}
}
public static void listRootsDemo()
{
File[] files = File.listRoots();
for(File f : files)
{
System.out.println(f);
}
}
}
列出指定目录下文件或者文件夹,包含子目录中的内容。
也就是列出指定目录下所有的内容。
因为目录中还有目录,只要使用同一个列出目录功能的函数完成即可。
在列出过程中出现的还是目录的话,还可以再次调用本功能。
也就是函数自身调用自身。
这种表现形式,或者称为编程手法,称为递归。
递归要注意:
1,限定条件
2,要注意递归的次数。尽量避免内存溢出。
import java.io.*;
class FileDemo3
{
public static void main(String[] args)
{
File dir = new File("d:\\java0217");
showDir(dir,0);
}
public static String getLevel(int level)
{
StringBuilder sb = new StringBuilder();
sb.append("|--");
for (int x=0; x<level; x++ )
{
//sb.append("|--");
sb.insert(0," ");
}
return sb.toString();
}
public static void showDir(File dir,int level)
{
System.out.println(getLevel(level)+dir.getName());
level++;
File[] files = dir.listFiles();
for (int x=0; x<files.length ; x++ )
{
if(files[x].isDirectory())
showDir(files[x],level);
else
System.out.println(getLevel(level)+files[x]);
}
}
public static void toBin(int num)
{
if (num>0)
{
toBin(num/2);
System.out.println(num%2);
}
}
}
练习
将一个指定目录下的java文件的绝对路径,存储到一个文本文件中。
建立一个java文件列表文件。
思路:
1,对指定的目录进行递归。
2,获取递归过程所有的java文件路径。
3,将只写路径存储到集合中。
4,将集合中的数据写入到一个文件中。
<span style="font-size:14px;">import java.io.*;
import java.util.*;
class JavaFileList
{
public static void main(String[] args) throws IOException
{
File dir = new File("d:\\java0217");
List<File> list = new ArrayList<File>();
fileToList(dir,list);
//System.out.println(list.size());
File file = new File(dir,"javalist.txt");
writeToFile(list,file.toString());
}
public static void fileToList(File dir,List<File>list)
{
File[] files = dir.listFiles();
for(File file:files)
{
if(file.isDirectory())
fileToList(file,list);
else
{
if(file.getName().endsWith(".java"))
list.add(file);
}
}
}
public static void writeToFile(List<File> list,String javaListFile)throws IOException
{
BufferedWriter bufw = null;
try
{
bufw = new BufferedWriter(new FileWriter(javaListFile));
for(File f : list)
{
String path = f.getAbsolutePath();
bufw.write(path);
bufw.newLine();
bufw.flush();
}
}
catch (IOException e)
{
throw e;
}
finally
{
try
{
if(bufw!=null)
bufw.close();
}
catch (IOException e)
{
throw e;
}
}
}
}</span>
装饰设计模式:当想要对已有的对象惊醒功能增强时。
可以定义类,将已有对象传入,基于已有的功能,并提供加强功能,
那么自定义的该类成为装饰类。
装饰类通常会通过构造方法接受被装饰的对象。
并基于被装饰的对象提供能强的功能。
class Person
{
public void chifan()
{
System.out.println("吃饭");
}
}
class SuperPerson
{
private Person p;
SuperPerson(Person p)
{
this.p = p;
}
public void superChifan()
{
System.out.println("开胃酒");
p.chifan();
System.out.println("甜点");
System.out.println("来一根");
}
}
class PersonDemo
{
public static void main(String[] args)
{
Person p = new Person();
SuperPerson sp = new SuperPerson(p);
sp.superChifan();
}
}
Properties 是hashtabile的子类。也就是说它具备map集合的特点。而且他里面存储的键值对都是字符串。
是集合中和IO技术相结合的集合容器。
该对象的特点:可以用于键值对形式的配置文件。
那么在加载数据时,需要数据有拱顶格式:键=值
<span style="font-size:14px;">import java.io.*;
import java.util.*;
class PropertiesDemo
{
public static void main(String[] args) throws IOException
{
loadDemo();
}
public static void loadDemo()throws IOException
{
Properties prop =new Properties();
FileInputStream fis = new FileInputStream("info.txt");
//将流中的数据加载进集合。
prop.load(fis);
prop.setProperty("wangwu","21");
FileOutputStream fos = new FileOutputStream("info.txt");
prop.store(fos,"haha");
//System.out.println(prop);
prop.list(System.out);
fis.close();
fos.close();
}
//演示,如何将流中的数据存储到集合众多那个。
//想要将info.txt中的键值数据存到集合中进行操作。
/*
1,用一个流和info.txt文件关联。
2,读取一行数据,将该行数据用"="进行切割。
3,等号左边作为键,右边作为值。存入到Properties集合中即可。
*/
public static void method_1()throws IOException
{
BufferedReader bufr = new BufferedReader(new FileReader("info.txt"));
String line = null;
Properties prop = new Properties();
while ((line=bufr.readLine())!=null)
{
String[] arr = line.split("=");
//System.out.println(arr[0]+"..."+arr[1]);
prop.setProperty(arr[0],arr[1]);
}
bufr.close();
System.out.println(prop);
}
//设置和获取元素。
public static void setAndGet()
{
Properties prop = new Properties();
prop.setProperty("zhangsan","30");
prop.setProperty("lisi","39");
//System.out.println(prop);
String value = prop.getProperty("lisi");
//System.out.println(value);
Set<String> names = prop.stringPropertyNames();
for(String s : names)
{
System.out.println(s+":"+prop.getProperty(s));
}
}
}</span>
看TransStreamDemo
读取键盘录入
System.out:对应的是标准输出设备,控制台。
System.in :对应的是标准输入设备,键盘。
需求:
通过键盘录入数据。
当录入一行数据后,就将改行数据进行打印。
如果录入的数据是over,那么停止录入。
读取键盘录入
System.out:对应的是标准输出设备,控制台。
System.in :对应的是标准输入设备,键盘。
需求:
通过键盘录入数据。
当录入一行数据后,就将改行数据进行打印。
如果录入的数据是over,那么停止录入。
<span style="font-size:14px;">import java.io.*;
class ReadIn
{
public static void main(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')
{
String s = sb.toString();
if("over".equals(s))
break;
System.out.println(s.toUpperCase());
sb.delete(0,sb.length());
}
else
sb.append((char)ch);
}
}
}</span>
删除一个带内容的目录。
删除原理:
在window中,删除目录从里面往外删除的。
既然是从里面往外删除。就需要用到递归。
class RemoveDir
{
public static void main(String[] args)
{
File dir = new File("d:\\");
removeDir(dir);
}
public static void removeDir(File dir)
{
File[] files = dir.listFiles();
for (int x=0; x<files.length; x++ )
{
if(files[x].isDirectory())
removeDir(files[x]);
else
System.out.println(files[x].toString()+":-file-:"files[x].delete());
}
System.out.println(dir+"::dir::"+dir.delete());
}
}
用于记录应用程序运行次数。
如果使用次数已到,那么给出注册提示。
很容易想到的是:计数器。
可是该计数器定义在程序中,随着程序的运行而在内存中存在,并进行自增。
可是随着该应用程序的退出,该计数器也在内存中消失了。
下一次在启动该程序,有重新开始从0计数。
这样不是我们想要的。
程序即使结束,该计数器的值也存在。
下次程序启动会先加载该计数器的值并加1后再重新存储起来。
所以要建立一个配置文件。用于记录该软件的使用次数。
配置文件使用键值对的形式。
这咽便于月度数据,并才做数据。
键值对数据是map集合。
数据是以文件形式存储,使用io技术。
那么map+io-->properties.
陪着文件可以实现应用程序数据的共享。
<span style="font-size:14px;">import java.io.*;
import java.util.*;
class RunCount
{
public static void main(String[] args) throws IOException
{
Properties prop = new Properties();
File file = new File("count.ini");
if(!file.exists())
file.createNewFile();
FileInputStream fis = new FileInputStream(file);
prop.load(fis);
int count = 0;
String value = prop.getProperty("time");
if(value!=null)
{
count = Integer.parseInt(value);
if (count>=5)
{
System.out.println("您好,使用次数已到,拿钱");
return;
}
}
count++;
prop.setProperty("time",count+"");
FileOutputStream fos = new FileOutputStream(file);
prop.store(fos,"");
fos.close();
fis.close();
}
}</span>
通过刚才的键盘录入一行数据并打印七大写,发现其实就是读一行数据的原理。
也就是readLine方法。
能不能直接使用readLine方法来完成键盘录入的一行数据的读取呢?
readLine方法是字符流BufferedReader类中的方法。
而键盘录入的read方法是字节流InputStream的方法!
那么能不能将字节流转成字符流在使用字符流缓冲区的readLine方法呢?
import java.io.*;
class TransStreamDemo
{
public static void main(String[] args) throws IOException
{
//过去键盘录入对象。
//InputStream in = System.in;
//将字节流对象转成字符流对象,使用转换流。InputStreamReader
//InputStreamReader isr = new InputStreamReader(in);
//为了提高效率,将字符流进行缓冲区技术提高效率操作。使用BufferedReader
//BufferedReader bufr = new BufferedReader(isr);
//键盘录入最常见写法
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while ((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
}
}
1,
源:键盘录入。
目的:控制台。
2,需求:想把键盘录入的数据存储到一个文件中。
源:键盘。
目的:文件。
3,需求:想要将一个文件的数据打印在控制台上。
源:文件
目的:控制台
流操作的基本规律:
最痛苦的就是流对象有很多,不知道改用哪一个。
通过三个明确来完成。
1,明确源和目的。
源:输入流。InputStream Reader
目的:输出流。OutputStream Writer
2,操作的数据是否是纯文本。
是:字符流
不是:字节流
3,当体系明确后,在明确要使用那个具体的对象。
通过设备进行区分:
源设备:内存,硬盘,键盘
目的设备:内存,硬盘,控制台。
例1
将一个文本文件中数据存储到另一个文件中,复制文件。
源:因为是源,所以使用读取流。InputStream Reader
是不是操作文本文件。
是!这时就可以选择Reader
这样体系就明确了
接下来明确要是用该体系中的那个对象。
明确设备:硬盘。上一个文件。
Reader体系中一颗操作文件的对象是FileReader
是否需要提高效率:是!加入Reader体系中的缓冲区。 BufferedReader.
FileReader fr = new FileReader("a.txt");
BufferedReader bufr = new BufferedReader(fr);
目的:OutputStream Writer
是否是纯文本。
是!Writer
设备:硬盘,一个文件
Writer体系汇总可以操作文件的对象是FileWriter。
是否需要提高效率:是!加入Reader体系中的缓冲区。 BufferedWriter
FileWriter fw = new FileWriter("b.txt");
BuffererdWriter bufw = new BufferedWriter(fw);
2,需求:将键盘录入的数据保存到一个文件。
这个需求中源和目的都存在。
那么分别分析
源:InputStream Reader
是不是纯文本?是!Reader
设备:键盘。对应的对象是 System.in
不是选择Reader吗?System.in对应的不是字节流吗?
为了操作键盘的文本数据方便。转成字符流按照字符串操作是最方便的。
所以既然明确Reader,那么就将System.in转换成Reader。
用了Reader体系中转换流,InputStreamReader
InputStreamReader isr = new InputStreamReader(System.in);
需要提高效率吗?需要!BufferedReader
BufferedReader bufr = new BufferedReader(isr);
目的:OutputStream Writer
是否是纯文本?是!Writer
设备:硬盘,一个文件。使用 FileWriter
FileWriter fw = new FileWriter("x.txt");
需要提高效率吗?需要
BufferedWriter bufw = new BufferedWriter(fw);
************************************************
扩展一下,想要把录入的数据按照指定的编码表(utf-8),将数据存到文件中。
目的:OutputStream Writer
是否是纯文本?是!Writer
设备:硬盘,一个文件。使用 FileWriter
但是FileWriter是使用默认编码表。GBK
但是存储时,需要加入指定编码表utf-8。而指定的编码表只有转换流可以指定。
所以要使用的对象是OutputStreamWriter。
而该转换流对象要接受一个字节数出流。而且还可以操作文件的字节输出流。FileOutputStream
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("d.txt"),"utf-8");
需要高效吗?需要。
BufferedWriter bufw = new BufferedWriter(osw);
所以,记住。转换流什么时候使用。字符和字节之间的桥梁,通常,涉及到字符编码转换时。
需要用到转换流。
<span style="font-size:14px;">import java.io.*;
class TransStreamDemo2
{
public static void main(String[] args) throws IOException
{
/*
需求2
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("out.txt")));
String line = null;
while ((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
*/
/*
需求3
BufferedReader bufr = new BufferedReader(new InputStreamReader(new FileInputStream("Copypic.java")));
BufferedWriter bufw = new BufferedWriter(new OutputStreamWriter(System.out));
String line = null;
while ((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
bufw.write(line.toUpperCase());
bufw.newLine();
bufw.flush();
}
bufr.close();
*/
}
}
</span>
用于操作字节数组的流对象。
ByteArrayInputStream :在构造的时候,需要接受数据源,而且数据源是一个字节数组。
ByteArrayOutputStream:在构造的时候,不用定义数据目的,因为该对象中已经内部封装了可变长度的字节数组。
这就是数据目的地。
因为这两个流对象都操作的数组,并没有使用系统资源。
所以,不用进行close关闭。
在流操作规律讲解时:
原设备:
键盘 System.in ,硬盘 FileStream ,内存 ArrayStream。
目的设备:
控制台 System.out,硬盘 FileStream,内存 ArrayStream。
用流的读写思想操作数据。
编码:字符串变成字节数组。
解码:字节数组变成字符串。
String-->byte[];str.getBytes(charsetName);
byte[] -->String: new String(byte[],charsetName);
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接受的参数类型:
1,file对象 File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:
PrintWriter
import java.io.*;
class ByteArrayStream
{
public static void main(String[] args)
{
//数据源。
ByteArrayInputStream bis = new ByteArrayInputStream("ABCDEFG".getBytes());
//数据目的
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int by = 0;
while ((by=bis.read())!=-1)
{
bos.write(by);
}
System.out.println(bos.size());
System.out.println(bos.toString());
}
}
编码:字符串变成字节数组。
解码:字节数组变成字符串。
String-->byte[];str.getBytes(charsetName);
byte[] -->String: new String(byte[],charsetName);
import java.util.*;
class EncodeDemo
{
public static void main(String[] args) throws Exception
{
String s = "你好";
byte[] b1 = s.getBytes("GBK");
System.out.println(Arrays.toString(b1));
String s1 =new String(b1,"ISO8859-1");
System.out.println("s1="+s1);
//对s1进行iso8859-1编码。
byte[] b2 = s1.getBytes("iso8859-1");
System.out.println(Arrays.toString(b2));
String s2 = new String (b2,"gbk");
System.out.println("s2="+s2);
}
}
import java.io.*;
class EncodeStream
{
public static void main(String[] args) throws IOException
{
//writeText();
readText();
}
public static void readText() throws IOException
{
InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK");
char[] buf = new char[10];
int len = isr.read(buf);
String str = new String(buf,0,len);
System.out.println(str);
isr.close();
}
public static void writeText()throws IOException
{
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("utf.txt"),"UTF-8");
osw.write("你好");
osw.close();
}
}
打印流:
该流提供了打印方法,可以将各种数据类型的数据都原样打印。
字节打印流:
PrintStream
构造函数可以接受的参数类型:
1,file对象 File
2,字符串路径。String
3,字节输出流。OutputStream
字符打印流:
PrintWriter
RandomAccessFile
该类不是算是IO体系的子类。
而是直接继承自Object。
但是他是IO包中成员。因为他具备读和写的功能。
内部封装了一个数组。而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置。
同事可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,读写rw等。
如果模式为只读 r。不会创建文件。会去读取一个已存在的文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存在则不会覆盖。
文件的切割和合并!
该类不是算是IO体系的子类。
而是直接继承自Object。
但是他是IO包中成员。因为他具备读和写的功能。
内部封装了一个数组。而且通过指针对数组的元素进行操作。
可以通过getFilePointer获取指针位置。
同事可以通过seek改变指针的位置。
其实完成读写的原理就是内部封装了字节输入流和输出流。
通过构造函数可以看出,该类只能操作文件。
而且操作文件还有模式:只读r,读写rw等。
如果模式为只读 r。不会创建文件。会去读取一个已存在的文件,如果该文件不存在,则会出现异常。
如果模式rw。操作的文件不存在,会自动创建。如果存在则不会覆盖。
<span style="font-size:14px;">import java.io.*;
class RandomAccessFileDemo
{
public static void main(String[] args) throws IOException
{
readFile();
}
public static void readFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","r");
//调整对象中指针。
//raf.seek(8*1);
//太过指定的字节数
raf.skipBytes(8);
byte[] buf = new byte[4];
raf.read(buf);
String name = new String(buf);
int age = raf.readInt();
System.out.println("name="+name);
System.out.println("age="+age);
raf.close();
}
public static void writeFile_2()
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.seek(8*3);
raf.write("周期".getBytes());
raf.write(120);
raf.close();
}
public static void writeFile() throws IOException
{
RandomAccessFile raf = new RandomAccessFile("ran.txt","rw");
raf.write("李四".getBytes());
raf.write(97);
raf.close();
}
}</span>
文件的切割和合并!
<span style="font-size:14px;">import java.io.*;
import java.util.*;
class SplitFile
{
public static void main(String[] args) throws IOException
{
merge();
}
public static void merge()throws IOException
{
ArrayList<FileInputStream> al = new ArrayList<FileInputStream>();
for (int x=1; x<=2; x++)
{
al.add(new FileInputStream("c:\\splitfiles\\"+x+".part"));
}
final Iterator<FileInputStream> it = al.iterator();
Enumeration<FileInputStream> en = new Enumeration<FileInputStream>()
{
public boolean hasMoreElements()
{
return it.hasNext();
}
public FileInputStream nextElement()
{
return it.next();
}
};
SequenceInputStream sis = new SequenceInputStream(en);
FileOutputStream fos = new FileOutputStream("c:\\splitfiles\\0.jpg");
byte[] buf = new byte[1024];
int len = 0;
while ((len=sis.read(buf))!=-1)
{
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
public static void splitFile()throws IOException
{
FileInputStream fis = new FileInputStream("c:\\a.jpg");
FileOutputStream fos = null;
byte[] buf = new byte[1024*1024];
int len = 0;
int count = 1;
while ((len=fis.read(buf))!=-1)
{
fos = new FileOutputStream("c:\\splitfiles\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}</span>
有五个学生,每个学生有3门课的成绩,
从键盘输入以上数据(包括姓名,三门课成绩),
输入的格式:如:zhangsan,30,40,60计算出总成绩。
并把学生的信息和计算出的总分数高低顺序存放在磁盘文件”stud.txt“中。
1,描述学生对象。
2,定义一个可操作学生对象的工具类。
思想:
1,通过获取键盘录入一行数据,并将该行中的信息取出封装成学生对象。
2,因为学生有很多,那么就需要存储,使用到集合。因为要对学生的总分排序。
所以可以使用TreeSet.
3,将集合的信息写入到一个文件中。
<span style="font-size:14px;">import java.io.*;
import java.util.*;
class Student implements Comparable<Student>
{
private String name;
private int ma,cn,en;
private int sum;
Student(String name,int ma,int cn,int en)
{
this.name = name;
this.ma = ma;
this.cn = cn;
this.en = en;
sum = ma+cn+en;
}
public int compareTo(Student s)
{
int num = new Integer(this.sum).compareTo(new Integer(s.sum));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
public String getName()
{
return name;
}
public int getSum()
{
return sum;
}
public int hashCode()
{
return name.hashCode()+sum*78;
}
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name)&&this.sum==s.sum;
}
public String toString()
{
return "student["+name+","+ma+","+","+cn+","+en+"]";
}
}
class StudentInfoTool
{
public static Set<Student> getStudents()throws IOException
{
return getStudents(null);
}
public static Set<Student> getStudents(Comparator<Student> cmp)throws IOException
{
BufferedReader bufr =
new BufferedReader (new InputStreamReader(System.in));
String line = null;
Set<Student> stus = null;
if(comp==null)
stus = new TreeSet<Student>();
else
stus = new TreeSet<Student>(cmp);
new TreeSet<Student>(cmp);
while((line=bufr.readLine())!=null)
{
if("over".equals(line))
break;
String[] info = line.split(",");
Student stu = new Student(info[0],Integer.parseInt(info[1]),
Integer.parseInt(info[2]),
Integer.parseInt(info[3]));
stus.add(stu);
}
bufr.close();
return stus;
}
public static void write2File(Set<Student> stus)throws IOException
{
BufferedWriter bufw = new BufferedWriter(new FileWriter("stuinfo.txt"));
for(Student stu : stus)
{
bufw.write(stu.toString()+"\t");
bufw.write(stu.getSum()+"");
bufw.newLine();
bufw.flush();
}
bufw.close();
}
}
class StudentInfoTest
{
public static void main(String[] args) throws IOException
{
Comparator <Student> cmp = Collections.reverseOrder();
Set<Student> stus = StudentInfoTool.getStudents(cmp);
StudentInfoTool.write2File(stus);
}
}
</span>