【JAVA学习笔记】20 单例和文件IO流

2018.4.21

单例

需求:

在整个程序的运行过程中,有且只能有一个当前类的类对象存在。

单例思想。

方案1:

在整个程序的运行过程中,有且只调用一个构造方法

问题:

你知道只能调用一次,但是别人知道吗?
这里除了自己,别人都不会这么认为,任何一个调用者都可以非常简单的
通过new 关键字,借助于当前类的构造方法,创建一个新的对象,违背当前情况

解决:

让类外无法轻松的调用和这个构造方法,私有化构造方法

问题:

私有化之后的构造方法,在类外无法使用,如何在类外创建对象或者说获取对象???

环境:

构造方法不能用
类外没有对象
所有和对象有关的方法的都不能使用。

现在能够使用的方法只能是静态(static)方法

方案:

借助于静态(static)方法获取或者创建类对象。
该方法要提供给类外使用所以权限修饰符为public
调用时不能通过对象来调用,用类名调用,使用static修饰
该方法是要获取当前类的类对象,所以返回值应该是当前类对象对象 SingleDemo

方法名字:[getInstance(int num)]
参数要和类内私有话的构造方法所需参数一致:int num

问题:

南辕北辙,创建对象麻烦了,但是效果是一样的。

需求:

如果能判断当前程序当中有没有SingleDemo的类对象
如果没有,创建,调用私有化的构造方法
如果有,不创建。

需要一个变量来保存创建对象的地址
变量数据类型SingleDemo
位置:
	假设:
		1.用局部变量保存地址。
			不行。 每一个调用时,之前的局部变量已经被销毁了。
		2.用成员变量。
			不行。静态方法中不能使用非静态的成员变量。
		3.用静态成员变量

解决:

用静态成员变量来保存之前创建的对象地址

问题:

发现类外可以直接 通过类名来修改静态成员变量的数据

解决:

private修饰
	
class SingleDemo {
	int num;
	private static SingleDemo s = null;
	private SingleDemo(int num) {
		this.num = num;
	}
	public void test() {
		System.out.println(this.getClass()+"的test方法");
	}
	public static SingleDemo getInstance(int num) {
		//私有话的构造方法可以在类内使用
		if(s == null) {
			s = new SingleDemo(num);
		}
		return s;
		
	}
}
public class Demo1 {
	public static void main(String[] args) {
		//解决方案1
		//SingleDemo singleDemo = new SingleDemo();
		SingleDemo s1 = SingleDemo.getInstance(5);
		System.out.println(s1);
//		SingleDemo s = null;
		SingleDemo s2 = SingleDemo.getInstance(19);
		System.out.println(s2);
	}
}

结果:
    com.bitware.single.SingleDemo@5ecb5608
    com.bitware.single.SingleDemo@5ecb5608
    两个类对象是同一个。

IO流

Input Output
IO流的参照物:
	当前运行成语:
		从硬盘中读取数据到内存中使用:		input
		从程序的内存中将数据保存到硬盘中: output
		
		
		pipe 管道文件
		socket 套接字
		
	按照处理的数据单位来做划分:
		字节流:
				完全按照二进制编码格式,一个字节一个字节获取 -------迅雷下载
				
		字符流:
				其实也是字节操作,但是会考虑当前系统的编码问题
				会将读取的字节数据,根据当前使用的字符集进行翻译
				
				GBK  GB2312 BIG5(繁体 台湾香港) UTF8(国际编码) 
				字符流 = 字节流 + 解码
				
				

输入流和输出流

字节流和字符流

InputStream
	FileinputStream
OutputStream
	FileOutpuStream

Reader 
	FileReader
Writer
	FilrWriter

1.使用缓冲区效率更高,原因是解决了内存访问硬盘的次数过多,导致的时间上的浪费。
通常缓冲流使用的缓冲空间一般都是4KB或者8KB
2.FileWriter 不是直接把数据写入到磁盘,而是在内存中建立了一个缓冲区用于保存
用户想要写入到硬盘的数据,有三种情况才会真正的写入数据到硬盘:
	1>缓冲区满了
	2>调用了flush方法,清空缓冲区
	3>FileWriter输出管道关闭。
3.字节流和字符流选择
	字节流基本上可以满足所有的文件内容传输需求
	字符流,只用来处理记事本可以打开的可视化文件

输入字节流 FileInputStream

字节流:

输入字节流 input 从硬盘到内存的流向,读取数据操作
---| InputStream 所有字节流的基类/父类  抽象类(没有类对象,有些方法没有方法体)
------| FileInputStream 读取文件的输入字节流

获取文件的操作步骤:

1.找到文件
	是否是一个普通文件
	是否存在
	String字符串路径
2.创建FileInputStream 输入管道 resource 资源 
3.读取文件
4.关闭管道(资源)

输出字节流 FileOutputStream

写入文件的操作流程:

1.找到要操作的文件(可以存在,也可以不存在,但是要操作的文件必须有后缀名。)
2.创建输出管道
3.写入数据
4.关闭资源

---| OutPut 所有输出字节流的基类,父类,抽象类。

------| FileOutputStream 文件输出字节流

FileOutputStream注意事项:

1.使用OutputStream写入数据到文件中,该文件可以存在可以不存在,FileOutputStream是拥有创建文件的能力

2.默认情况下,FileOutputStream采用的是覆盖写入数据的方式,如果想要使用追加写
使用FileOutputStream(File file, boolean append),boolean决定是否添加追加写。

3.小写字母a,ascii码为97
	0110 0001
	写入的数据是353
	0000 0000 0000 0000 0000 0001 0110 0001
	
	写入的结果都是小写字母a
	因为FileOutputStream调用writeint b)方法,写入的数据其实是整个int数据
	内部二进制的低8位,高24位对于write方法来说是无效数据。
	
	汉字无法输入:
		因为一个汉字在GBK编码下占用的是2个字节,
		在UTF8编码下占用的是3个字节。


   public class demo2 {
	public static void main(String[] args) throws IOException {
		
		output();
		input();
	}
	public static void output() throws IOException {
		//创建文件也要抛出异常 因为可能没有创建权限。
		//1.赋给file2要写入的文件路径
		File file = new File("C:/aaa/6.txt");
		
		//2.判断文件是否存在 是否是一个普通文件
		if(!file.exists()||!file.isFile()) {
			throw new FileNotFoundException();
		}
		
		//3.创建字节流输出管道,默认覆盖写入 如果要使用追加写,考虑需要使用FileOutputStream(File file ,boolean append)
		FileOutputStream fos = new FileOutputStream(file,true);
		
		//3.写入数据
		// write方法只能写入Ascii码值或者byte [] 数组一个字节  所以要将字符串转换成数组再写入。
//		fileOutputStream.write('H');
//		fileOutputStream.write('e');
//		fileOutputStream.write('l');
//		fileOutputStream.write('l');
//		fileOutputStream.write('v');
//		fileOutputStream.write('b');
//		fileOutputStream.write(97); ASCII码 并不能直接写入数字
		
		//定义一个要写入的字符串。
		String str = "我喜欢你啊";	
		//把字符串转换成Byte[] 数组
		byte[] buffer = str.getBytes();//返回值为一个Byte数组
		
		fos.write(buffer);
		//4.关闭资源
		fos.close();	
	} 
	public static void input() throws IOException {
		//1.赋给file2要读取的文件路径
		File file2 = new File("C:/aaa/6.txt");
		
		//2.判断文件是否存在 是否是一个普通文件
		if(!file2.exists()||!file2.isFile()) {
			throw new FileNotFoundException();
			
		}
		//3.创建字节流输入管道
		FileInputStream fis = new FileInputStream(file2);
		
		//4.准备缓冲区读取文件
		int length = -1;
		byte[] buffer1 = new byte[1024];//存储的缓冲区字节个数
		
		//按照read()内规定的数据个数来读取管道所拥有的路径指向的文件数据。
		while((length = fis.read(buffer1)) != -1) {
			System.out.println(new String(buffer1));
			
		}
		//4.关闭管道资源
		fis.close();
	
	}
}

字节流拷贝图片实例

public class CopyImage {
    	public static void main(String[] args) throws IOException {
    	//1.找到源文件
    		File srcFile = new File("C:\\Users\\bitware13\\Desktop\\1.jpg");
    	//判断源文件是否存在,是否是一个普通文件
    		if(!srcFile.exists()||!srcFile.isFile()) {
    			throw new FileNotFoundException();
    		}
    	//2.确定要拷贝的地址
    		File dstFile = new File("C:\\Users\\bitware13\\Desktop\\2.jpg");
    		
    	//3.打开input和output通道
    		FileInputStream fileInputStream = new FileInputStream(srcFile);
    		FileOutputStream fileOutputStream =new FileOutputStream(dstFile);
    	//4.利用缓冲从硬盘上读取数据
    		int length = -1;//读取到的字节个数
    		byte[] buffer = new byte[1024*4];//缓冲区4Kb/8Kb左右符合我们硬盘的扇区
    		
    		while ((length = fileInputStream.read(buffer)) != -1) {//把数组中内容写进去
    			//fileOutputStream.write(buffer);会有可能导致复制之后的文件会变大。原因是从硬盘读取数据
    			//时,最后一次有可能无法填充满整个缓冲区,但是写入时没有判断缓冲区里面的数据是不是都是图片数据。
    			fileOutputStream.write(buffer, 0, length);
    			
    		}
    	//5.关闭资源,先开后关,后开先关。
    		fileOutputStream.close();
    		fileInputStream.close();
    		
    	}
    }

输入字符流 FileReader

Io input Output

字节流:

InputStream
	FileInputStream
OutputStream
	FileOutputStream

字符流:

字符流 = 字节流 + 解码

字符流读取数据,输入字符流

---| Reader 输入字符流的基类/超类 抽象类。
-----| FileReader 读取文件的输入字符流

使用方式:

1.找到文件
	判断文件是否存在,是否是一个普通文件
2.建立FileReader读取通道
3.读取数据
4.关闭资源

public class Demo1 {
	public static void main(String[] args) throws IOException {
		//readerTest1();
		readerTest2();
	}
	
	public static void readerTest2() throws IOException {
		//1.找到文件
		File file = new File("C:\\aaa\\2.txt");
		
		//判断文件是否存,是否是个文件
		if(!file.exists() || !file.isFile()) {
			throw new FileNotFoundException();
		}
		//2.建立FileReader 输入字符流管道
		FileReader fReader = new FileReader(file);
		
		//3.建立缓冲区,利用缓冲区读取数据,创建字符数组
		int length = -1;//用于保存读取到的字符个数
		char[] buffer = new char[1024];
		
		while((length = fReader.read(buffer)) != -1) {
			System.out.println(new String(buffer));
		}
	//4.关闭资源
		fReader.close();
	}
	

     }
/*

输出字节流 FileWriter

输出字符流:

---| Writer 输出字符流的基类/父类 抽象类
	------| FileWriter 文件操作的输出字符流

操作流程:

1.找到目标文件’
	2.建立输出管道
	3.写入数据】
	4.关闭资源

[发现]

1.如果写入的数据不多,程序如果中止,在目标文件中没有任何的数据,但是程序继续运行,
数据会写入到文件中
2.如果写入的数据很大,程序如果中止 ,可能会在目标文件中写入一部分数据,当程序继续运行
之后的数据也会写入到文件中。

java字符流的一个特征:

目的是减少对于磁盘的写入操作,写入数据到硬盘是对硬盘有一定损耗的,所以JAVA中就使用了一种缓冲机制
当调用FileWrtier的writer方法,并不是直接写入数据到硬盘,而是现行保存在FileWriter类对象
里面的缓冲区中,在这个缓冲区是一个【字符】数组,这个数组默认的元素格式【1024个字符】

有三种情况,可以直接把数据写入到文件中:

1.关闭FileWriter资源
	2.缓冲区满了,会直接清空缓冲区,把数据写入到硬盘众
	3.调用flash方法,立即清空缓冲区,直接写入数据到硬盘。

注意事项:

FileWriter在操作文件时,如果文件不存在,畏怯文件夹权限允许,可以直接创建文件,
	如果想要追加写,调用
	FileWriter(File file ,boolean append);

public class Demo1 {
	public static void main(String[] args) throws IOException {
		writerTest();
	}
	
	public static void writerTest() throws IOException {
		//1.找到或创建一个要写入数据的文件
		File file = new File("C:/aaa/writerTest.txt");
		
		//2.建立管道
		FileWriter fWriter = new FileWriter(file);
		
		//3.准备要写入的数据
		fWriter.write(new String("今天清明节很难受兄弟"+"今天清明节很难兄弟"	));
		
		//4.关闭资源
		fWriter.close();
	}
}

字符流拷贝图片弊端

每一次复制之后的文件都是缺少固定的字符个数

是因为使用字符流读取数据时,数据会进行一个解码的过程,根据当前系统规定默认字符集你隐形编码
而在解码的过程中,如果解码的数据不能和当前字符集里面的数据进行匹配,那么对于字符流来说
这是一个无效数据,会被扔掉,这就是为什么复制图片无法成功,一致缺少数据。

** 字节流基本上可以用在所有的文件操作中,字符流只能用到TXT文本可以打开的可视化文件中。**

public class copyImage {
	public static void main(String[] args) throws IOException {
		//1.找到源文件
		File srcFile = new File("C:\\Users\\bitware13\\Desktop\\2.jpg");
		
		if(!srcFile.exists() || !srcFile.isFile()) {
			throw new FileNotFoundException();
		}
		
		//2.确定目标文件
		File dstFile = new File("C:\\Users\\bitware13\\Desktop\\3.jpg");
		
		//3.打开读取和写入通道
		FileReader fileReader = new FileReader(srcFile);
		FileWriter fileWriter = new FileWriter(dstFile); 
		
		//4.准备字符缓冲区
		int length = -1;
		char[] buffer = new char[1024];
		
		while((length = fileReader.read(buffer)) != -1) {
			fileWriter.write(buffer);
		}
		
		//5.关闭资源
		
		fileWriter.close();
		fileReader.close();
		
		
		
	}
}

猜你喜欢

转载自blog.csdn.net/u013182992/article/details/80472030