io流
(类和接口存在于java.io包中)
一、File类操作:
1、File类介绍:
File类是IO包中唯一表示磁盘文件和磁盘目录的对象的路径.
该类包含了创建,删除文件,重命名文件,判断文件读写权限以及文件是否存在,查询等功能方法.
只能设置和获取文件本身的信息,不能设置和获取文件的内容.
2、路径分隔符,属性分隔符:
(1)Unix: 使用”/”,来分割目录路径. 使用:来分割属性.
(2)Windows: 使用”\”,来分割目录路径.但是在Java中一个”\”表示转义,在Windows平台的Java代码中表示一个路径,就得使用两个\\. 但是Windows支持/. 使用;来分割属性.
(但是我经常用的是File。separator。eg:String path2 = "d:"+File.separator+"temptest"+File.separator+"2.txt";)
3、File类中的方法:
文件操作:
boolean isFile() :是否是文件
boolean createNewFile() :创建新的文件
static File createTempFile(String prefix, String suffix) :创建临时文件
boolean delete() :删除文件
void deleteOnExit() :在JVM停止时删除文件
boolean exists():判断文件是否存在
boolean renameTo(File dest) :重新修改名称
目录操作
boolean isDirectory() :判断是否是目录
boolean mkdir() :创建当前目录
boolean mkdirs() :创建当前目录和上级目录
String[] list() :列出所有的文件名
File[] listFiles() :列出所有文件对象
static File[] listRoots() :列出系统盘符
4、需求:列出指定目录中所有的文件,包括子文件夹中的所有文件(使用递归算法(recursion))
Demo:
public class FileDemo { public static void main(String[] args) { String path = "D:\\Java笔记\\基础笔记"; MyUtils.readAllFile(path); } } class MyUtils{ public static void readAllFile(String path){ File f = new File(path); File[] fs = f.listFiles(); for(int i=0;i<fs.length;i++){ if(fs[i].isDirectory()){ System.out.println(fs[i]+"------------------------------"); readAllFile(fs[i].toString()); }else{ System.out.println(fs[i]); } } } }
二、输入和输出:
1、io流分类:
1):根据流向划分: 输入流和输出流.
2):根据数据的单位划分: 字节流和字符流.
3):根据功能的划分:节点流和包装流.
2、四大基流:(字节输出流,字节输入流,字符输出流,字符输入流)
四大基流都是抽象类: 其他流都是继承于这四大基流的,我们不能创建四大基流的对象,只能创建其子类对象.
无论是什么流,都有close方法,用来关闭资源. 如果操作文件,就得开通一个流对象关联我们得磁盘文件,如果不关闭资源,那么磁盘的文件一直被程序所引用着,不能删除,也不能更改.
三、操作io流的模板:
1、创建源或者目标对象(挖井).
拿文件流举例:
输入操作: 把文件中的数据流向到程序中,此时文件是源,程序是目标.
输出操作: 把程序中的数据流向到文件中,此时文件是目标,程序是源.
2、创建IO流对象(水管):
输入操作: 创建输入流对象.
输出操作: 创建输出流对象.
3、具体的IO操作:
输入操作: 输入流对象的read方法.
输出操作: 输出流对象的write方法.
4、关闭资源(勿忘): 一旦资源关闭之后,就不能使用流对象了,否则报错.
输入操作: 输入流对象.close();
输出操作: 输出流对象.close().
操作IO流的六字箴言: 读进来,写出去.
四、字节流、字符流:
1、字符流和字节流的区别:
(1)字节流操作的基本单元为字节;字符流操作的基本单元为Unicode码元。
(2)字节流默认不使用缓冲区;字符流使用缓冲区。
(3)字节流通常用于处理二进制数据,实际上他可以处理任意类型的数据,但不支持直接写入或读取Unicode码元;字符流通常处理文本数据,但支持写入或读取Unicode码元。
2、字节流输出和输入:
Demo:
public class InputStreamDemo {
public static void main(String[] args) throws IOException {
//字节输入流
String path = "d:"+File.separator+"test"+File.separator+"002.txt";
//当需要使用file中的函数时就创建file
File f = new File(path);
InputStream in = new FileInputStream(path);
/*byte[] b = new byte[(int) len];
long len = f.length();
in.read(b);
in.close();
System.out.println(new String(b));*/
//不能确定那个文件内容有多少
byte[] b = new byte[1024];
int len = 0;
while((len=in.read(b))!=-1){
System.out.println(new String(b,0,len));
}
}
}
public class OutputStreamDemo1 {
//字节输出流:
public static void main(String[] args) throws IOException {
String info = "我是好人!";//D:\test\001.txt
String data = "\r\n大家都知道。";
//字节输出:是输入还是输出以程序为参考,将数据输入程序中就为输入流,反只将数据从程序中输出到其他地方就是输出流
String path = "D:"+File.separator+"test"+File.separator+"001.txt";
OutputStream out = new FileOutputStream(path,true);//表示追加文件内容。
out.write(data.getBytes());
//out.close();
}
}
3、字符流输出和输入:
Demo:
//输出流:
File f = new File("d:"+File.separator+"text"+File.separator+"test2.text");
Writer out = new FileWriter(f,true);
String t = "\r\n我爱我的祖国";
out.write(t);
out.close();
//输入流:
FileReader in = new FileReader(f);
char[] c = new char[(int)f.length()];
//第一种方式
//int len=in.read(c);
//第二种方式
int temp;
int len = 0;
while((temp = in.read()) != -1){
c[len] = (char)temp;
len++;
}
五、flush操作(输出流中都有):
计算机访问外部设备(磁盘文件),要比直接访问内存慢很多,如果每次write都要直接写出到磁盘文件中,CPU都会花更多的时间,此时我们可以准备一个内存缓冲区,程序每次write方法都是直接写到内存缓冲区中,当内存缓冲区满后,系统才把缓冲区内容一次性写出给磁盘文件.
使用缓冲区的好处:
1:提高CPU使用率.
2:有机会回滚写入的数据.
对于字节流,flush方法不是都有作用(部分字节流才有作用,缓冲流),对于字符流都起作用.
如果我们调用close方法,系统在关闭资源前,会先调用flush方法.
操作系统使用-1表示磁盘文件的结尾标记.
缓冲区大小一般使用容量整数倍,可以提高IO性能.
六、内存操作流(适配器模式):
把数据先临时存在数组中,待会再从数组中获取出来.
1、字节内存流: ByteArrayInputStream/ByteArrayOutputStream
2、字符内存流: CharArrayReader/CharArrayWriter
3、字符串流:StringReader/StringWriter(把数据临时存储到字符串中)
Demo:
public class ByteArrayDemo {
public static void main(String[] args) {
String info = "wo shi haoren";
// 内存输入流
//将小写转换为大写
ByteArrayInputStream bais = null;
ByteArrayOutputStream baos = null;
try {
bais = new ByteArrayInputStream(info.getBytes());
baos = new ByteArrayOutputStream();
int temp = 0;
while((temp=bais.read())!=-1){
char c = (char)temp;
char cc = Character.toUpperCase(c);
baos.write(cc);
}
System.out.println(baos.toString());
} catch (Exception e) {
// TODO: handle exception
}finally{
try {
bais.close();
baos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
七、转换流:
转换流:把字节流转成字符流:
InputStreamReader:把字节输入流转成字符输入流.
OutputStreamWriter:把字节输出流转成字符输出流.
为什么有字节转字符流,没有字符转字节流.
字节流可以操作一切文件(纯文本文件/二进制文件).
字符流是用来操作中文纯文本使用的,本身是对字节流的增强.
八、管道流:
定义:实现两个线程之间的数据交互.
PipedInputStream/PipedOutputStream/PipedReder/PipedWriter
Demo:
public class PipedDemo {
public static void main(String[] args) {
//管道流
OutPip op = new OutPip();
Receive rec = new Receive();
Thread th1 = new Thread(op);
Thread th2 = new Thread(rec);
th1.start();
th2.start();
try {
op.getOut().connect(rec.getIn());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//op.getOut().connect(snk);
}
}
//接收线程
class Receive implements Runnable{
private PipedInputStream in;
public Receive() {
this.in = new PipedInputStream();
}
@Override
public void run() {
byte[] b = new byte[1024];
try {
this.in.read(b);
System.out.println(new String(b));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
this.in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public PipedInputStream getIn() {
return in;
}
}
//发送线程
class OutPip implements Runnable{
private PipedOutputStream out;
public OutPip() {
this.out = new PipedOutputStream();
}
@Override
public void run() {
String info = "好人是我!";
try {
this.out.write(info.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
this.out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public PipedOutputStream getOut() {
return out;
}
}
九、打印流(只能是输出流):
1、PrintStream: 字节打印流
2、PrintWriter: 字符打印流
3、使用打印流作为输出流,此时的输出操作会特别简单,因为在打印流中:a):提供了print方法:打印不换行 b):提供了println方法:打印再换行
print和println方法可以支持打印/输出各种数据类型的数据,记住void println(Object x) 即可
打印流中的格式化输出(prinf方法):
System.out.println();其实就相当于PrintStream ps = System.out; ps.println()
Demo:
public class PrintStreamDemo {
public static void main(String[] args) {
String path = "d:"+File.separator+"test"+File.separator+"007.txt";
PrintStream ps = null;
try {
ps = new PrintStream(new FileOutputStream(path,true));
ps.println("好人!");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
PrintWriter pw = new PrintWriter(path);
pw.print("坏人");
pw.flush();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
4、打印流的格式化输出(装饰设计模式)
Demo:
File f = new File("d:"+File.separator+"text"+File.separator+"test6.text");
PrintStream ps = new PrintStream(new FileOutputStream(f));
PrintWriter pw = new PrintWriter(new FileWriter(f));
String name = "张三";
int age = 20;
double score = 89.7;
char sex = 'F';
//字节打印流格式化输出
// ps.printf("name:%s,age:%d,score:%f,sex:%c",name,age,score,sex);
// ps.close();
//字符打印流格式化输出
pw.printf("name:%s,age:%d,score:%f,sex:%c",name,age,score,sex);
pw.close();
十、标准输入/输出流:
1、标准的输入: 通过键盘录入数据给程序.
2、标准的输出: 在屏幕上显示程序数据.
3、在System类中有两个常量:
1):InputStream in = System.in;
2):PrintStream out = System.out;
4、标准流的重定向操作:
1):标准的输入: 通过键盘录入数据给程序.
重新指定输入的源不再是键盘,而是一个文件.
static void setIn(InputStream in) 重新分配“标准”输入流。
此后,System.in数据的来源就是通过setIn制定的源.
2):标准的输出: 在屏幕上显示程序数据.
重新指定输出的目标不再是屏幕,而是一个文件.
static void setOut(PrintStream out) 重新分配“标准”输出流。
Demo1:
public class OutDemo1 {
public static void main(String[] args) throws IOException {
OutputStream out = System.out;//标准输出流
out.write("我是好人".getBytes());
Scanner sc = new Scanner(System.in);//标准的输入
OutputStream err = System.err;
err.write("错了!".getBytes());
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String temp = br.readLine();
System.out.println(temp);
}
}
Demo2:
/**
* 标准输入输出流的重定向
* @author Administrator
*
* 本质是一个字节的输出入流,所以可以改变流的方向
*
*/
public class OutInDemo {
public static void main(String[] args) {
//PrintStream out = System.out;
//out.print("祖国万岁!");
System.out.println("祖国万岁!");
//重定向
String path = "d:"+File.separator+"test"+File.separator+"mylogs.txt";
PrintStream ps;
try {
ps = new PrintStream(new FileOutputStream(path,true));
System.setOut(ps);
//System.out.println("祖国万岁!");
int a = 3/0;
} catch (Exception e) {
//e.printStackTrace();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println(sdf.format(new Date()));
System.out.println(e);
}
}
}
十一、扫描器类(Scanner):
Demo:
public class ScannerDemo {
/**
* @param args
* @throws FileNotFoundException
*/
public static void main(String[] args) throws FileNotFoundException {
//Scanner scan = new Scanner(System.in);//从键盘接收数据
Scanner scan = new Scanner(new FileInputStream("D:"+File.separator+"text"+File.separator+"text9.text"));//从文件输入
//改变以空格做为分隔符,如果不改就只能输出空格之前的
scan.useDelimiter("\n");
System.out.print("setin:");
String s = scan.next();
System.out.print(s);
}
}
十二、合并流:
SequenceInputStream:就是把多个输入流,合并成一个流对象
Demo:
public class SequenceInputStreamDemo {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
/*String path1 = "D:"+File.separator+"soft"+File.separator+"test1.txt";
String path2 = "D:"+File.separator+"soft"+File.separator+"test2.txt";
String path3 = "D:"+File.separator+"soft"+File.separator+"test3.txt";
File f1 = new File(path1);
File f2 = new File(path2);
File f3 = new File(path3);
FileInputStream is1 = new FileInputStream(f1);
FileInputStream is2 = new FileInputStream(f2);
FileOutputStream is3 = new FileOutputStream(f3);
SequenceInputStream s = new SequenceInputStream(is1, is2);
int temp=0;
while((temp=s.read())!=-1){
is3.write(temp);
}
s.close();
is1.close();
is2.close();
is3.close();
*/
String path1 = "D:"+File.separator+"soft"+File.separator+"test1.txt";
String path2 = "D:"+File.separator+"soft"+File.separator+"test2.txt";
String path3 = "D:"+File.separator+"soft"+File.separator+"test3.txt";
String path4 = "D:"+File.separator+"soft"+File.separator+"test4.txt";
File f1 = new File(path1);
File f2 = new File(path2);
File f3 = new File(path3);
File f4 = new File(path4);
FileInputStream is1 = new FileInputStream(f1);
FileInputStream is2 = new FileInputStream(f2);
FileInputStream is4 = new FileInputStream(f4);
FileOutputStream is3 = new FileOutputStream(f3);
ArrayList<FileInputStream> ar = new ArrayList<FileInputStream>();
ar.add(is1);
ar.add(is2);
ar.add(is4);
Enumeration<FileInputStream> et = Collections.enumeration(ar);
SequenceInputStream s = new SequenceInputStream(et);
int temp=0;
while((temp=s.read())!=-1){
is3.write(temp);
}
s.close();
is1.close();
is2.close();
is3.close();
}
}
合并器/分割器:
Demo:
public class SplitDemo {
public static void main(String[] args) {
String path = "d:"+File.separator+"test"+File.separator+"files";
try {
FileUtils.merge(path);
} catch (IOException e) {
e.printStackTrace();
}
}
}
class FileUtils{
//合并器
public static void merge(String path) throws IOException{
File f = new File(path);
File[] fs = f.listFiles();
/*for (int i = 0; i < fs.length; i++) {
System.out.println(fs[i].getName());
}*/
ArrayList<InputStream> list = new ArrayList<InputStream>();
for (File x : fs) {
//System.out.println(x);
InputStream in = new FileInputStream(x);
list.add(in);
//in.close();
}
Enumeration<InputStream> enm = Collections.enumeration(list);
SequenceInputStream sis = new SequenceInputStream(enm);
OutputStream out = new FileOutputStream(path+File.separator+"temp.jpg");
byte[] b = new byte[1024];
int len = 0 ;
while((len=sis.read(b))!=-1){
out.write(b, 0, len);
}
out.close();
sis.close();
}
//分割器
public static void split(String path,int size) throws IOException{
InputStream in = new FileInputStream(path);
String tempPath = "d:"+File.separator+"test"+File.separator+"files"+File.separator;
byte[] b = new byte[size];
int len = 0;
int count = 0;
while((len=in.read(b))!=-1){
OutputStream out = new FileOutputStream(tempPath+(++count)+".me");
out.write(b, 0, len);
out.close();
}
in.close();
}
}
十三、Properties集合类配置文件:
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
Properties prs = new Properties(); //Properties():创建一个空属性列表
prs.setProperty("os-name", "windows"); //etProperty():
prs.setProperty("os-version", "win10");
prs.setProperty("os-time","2017-10-23");
String path = "d:"+File.separator+"temptest"+File.separator+"5.txt";
File f = new File(path);
OutputStream ops = new FileOutputStream(f);
prs.store(ops, "key=values");//store:将properties表中的属性列表写入输出流
ops.close();
//读出并修改配置文件
String path1 = "d:"+File.separator+"temptest"+File.separator+"5.txt";
File f1 = new File(path1);
InputStream ips = new FileInputStream(f1);
Properties pros = new Properties();
pros.load(ips);//load:读取属性列表
pros.setProperty("os-version", "win7");
OutputStream ops1 = new FileOutputStream(f1);
pros.store(ops1,"sd");
//pros.list(System.out);//list:将属性列表输出到指定的输出流
//ips.close();
}
}
十四、压缩流:
public class ZipUtil {
public static void main(String[] args) {
String path = "D:"+File.separator+"test";
try {
ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream("D:"+File.separator+"tt.zip"));
new ZipUtil().zip(new File(path),"file",zipOut) ;
zipOut.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void zip(File inputFile,String str,ZipOutputStream zipFile) throws IOException{
//判断文件是否为文件夹
if(inputFile.isDirectory()){
File[] files = inputFile.listFiles();
zipFile.putNextEntry(new ZipEntry(str+"/")); //使用指定名字创建压缩条目
str = str.length()==0 ? "":str+"/";
for (int i=0;i<files.length;i++) {
zip(files[i],str+files[i].getName(), zipFile); //递归调用压缩方法
}
}else{
InputStream in = new FileInputStream(inputFile);
//开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处。
ZipEntry zipname = new ZipEntry(str);
zipFile.putNextEntry(zipname);
byte[] buff = new byte[1024];
int len = 0;
while((len = in.read(buff))!=-1){
zipFile.write(buff, 0, len);
}
in.close();
}
}
//解压文件:
public void unzip(String zipFileName, String outputDirectory) {
System.out.println("正在解压···");
try {
ZipInputStream in = new ZipInputStream(new FileInputStream(zipFileName));
ZipEntry z = in.getNextEntry();
while (z != null) {
System.out.println("正在解压:" + z.getName());
//创建以zip包文件名为目录名的根目录
File f = new File(outputDirectory);
f.mkdirs();
if (z.isDirectory()) {
String name = z.getName();
// name = name.substring(0, name.length() - 1);
f = new File(outputDirectory + File.separator + name);
f.mkdirs();
} else {
f = new File(outputDirectory + File.separator + z.getName());
f.createNewFile();
FileOutputStream out = new FileOutputStream(f);
byte[] buff = new byte[1024];
int len ;
while ((len = in.read(buff)) != -1) {
out.write(buff,0,len);
}
out.close();
}
z = in.getNextEntry(); //读取下一个ZipEntry
}
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
十五、序列化与反序列化:
1、序列化: 指把堆内存中的Java对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络的节点(在网络上传输),我们把这个过程称之为序列化.
2、反序列化:把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象的过程.
3、为什么要做序列化:
1):在分布式系统中,需要共享的数据的JavaBean对象,都得做序列化,此时需要把对象再网络上传输,此时就得把对象数据转换为二进制形式.
以后存储在HttpSession中的对象,都应该实现序列化接口(只有实现序列化接口的类,才能做序列化操作).
2):服务钝化:如果服务发现某些对象好久都没有活动了,此时服务器就会把这些内存中的对象,持久化在本地磁盘文件中(Java对象-->二进制文件).
如果某些对象需要活动的时候,现在内存中去寻找,找到就使用,找不到再去磁盘文件中,反序列化我们得对象数据,恢复成Java对象
4、需要做序列化的对象的类,必须实现序列化接口:java.io.Serializable接口(标志接口[没有抽象方法]).
底层会判断,如果当前对象是Serializable的实例,才允许做序列化. boolean ret = Java对象 instanceof Serializable;
5、使用对象流来完成序列化和反序列化操作:
ObjectOutputStream: 通过writeObject方法做序列化操作的.
ObjectInputStream: 通过readObject方法做反序列化操作的.
做反序列化操作必须存在对象的字节码对象.
6、transient关键字(这个属性就不会在被序列化,序列化主要是对属性的序列化)
Eg: private transient String name = "haoren";
Demo:
/**
* 对象序列化:就是将对象作为一个整体,进行输入输出或传递。
* @author Administrator
*
*/
public class SerializableDemo1 {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
User user = new User(1,"好人","蛟龙港");
String path = "d:"+File.separator+"test"+File.separator+"object.txt";
//序列化:
ObjectOutputStream oops = new ObjectOutputStream(new FileOutputStream(path));
oops.writeObject(user);
oops.close();
//反序列化:
ObjectInputStream oips = new ObjectInputStream(new FileInputStream(path));
User userNew = (User) oips.readObject();
System.out.println(userNew.getName());
}
}
十六、数据流:
数据流,提供了可以读/写任意数据类型的方法:
DataOutputStream: 提供了 writeXxx(xxx value)方法.
DataInputStream: 提供了 readXxx()方法.
【注】 writeXxx和readXxx必须要对应起来, writeByte写出的数据,此时只能使用readByte读取回来.
Demo:
/**
* 读写基本数据类型的流
* @author Administrator
*
*/
public class DataOutputStreamDemo {
public static void main(String[] args) {
int number = 2;
double score = 3.1415;
String path = "d:"+File.separator+"test"+File.separator+"008.txt";
try {
DataInputStream dis = new DataInputStream(new FileInputStream(path));
int data1 = dis.readInt();
char data2 = dis.readChar();
double data3 = dis.readDouble();
System.out.println((data1+1)+","+data2+","+data3);
dis.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}