2O2l年6月IO日出生的女孩命运?

单色仪波长定标中狭缝设置的影响分析

高放12,翟文超、李健军、谢臣瑜1

(1.中国科学院安徽光学精密机械研究所通用光学定标与表征技术重点实验室,安徽合肥230031#

2.中国科学技术大学,安徽合肥230031)

摘要:单色仪作为一种分光仪器,在传感器的辐射定标等方面具有重要应用。在实际应用过程 中,其波长和带宽的设置对传感器的精确定标具有重要影响。使用低压汞灯作为波长标准光源,通过对其特征谱线扫描的方法,研究了传感器定标过程中,设置单色仪不同的狭缝宽度,对传感 器精确定标具有重要影响。结果显示,当出射入射狭缝相同,同时改变其宽度的情况下,与典型 校准状态(出射入射狭缝宽度设置为0. 5m m)相比,波长偏差量达到0. 17 n m;当入射狭缝与出射 狭缝不一致时,与典型校准状态相比,波长偏差量达到0. 18 n m;当光源未充满入射狭缝与充满入 射狭缝相比,最大误差达到0.02 n m,该影响几乎可以忽略。在相关的传感器光谱辐射定标实验研究中,单色仪的定标精度和准确性评估等方面具有重要应用。

关键词:单色仪;波长带宽;波长校准;单色仪狭缝

收稿日期= ;修回日期:

基金项目:国家自然科学基金()

           Java对数据的操作是通过流的对象。

           Java用于操作流的对象都在IO包中。

  流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。

  根据处理数据类型的不同分为:字符流和字节流        

  根据数据流向不同分为:输入流和输出流

       字符流的由来:在早期IO包中存在的都是字节流,因为无论是内存还是硬盘中的文件,它们都是以字节的形式传输或保存。随着编码技术的不断提高,人们陆续创造出了不同的编码表,【如:ASCII(美国信息交换标准代码),gb2312, GBK, unicode(国际标准码表:无论哪个字符都用两个字节表示),utf-8(国际标准码表的优化表:根据字符使用的字节长度来调整字节位数)】,但是当存储数据的计算机和取出数据的计算机使用的编码表不同时,就会造成取出数据的乱码情况。

  为了解决这个乱码问题,Java就在字节流的基础上产生了一个字符流,而这个字符流的好处就是当读取数据时可以自己指定编码表。 

  字节流和字符流的区别:

  (1)读写单位不同:字节流以字节(8bit)为单位。字符流以字符为单位,根据码表映射字符,一次可能读多个字节。

           字节流:一次读入或读出是8位二进制,分别操作字节和字节数组。字符流:一次读入或读出是16位二进制,分别操作字符,字符数组或字符串。

  (2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。

  (3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候是会用到缓冲区的,是通过缓冲区来操作文件。(因为一个字符通常是由两个字节组成的,所以当读取了一个字节时,无法查找正确的字符)

    结论:只要是处理纯文本数据,就优先考虑使用字符流, 除此之外建议使用字节流。但字节流是通用的。

    注意:由这四个类派生出来的子类名称都是以其父类作为子类名的后缀。

  对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。

  Writer 写入字符流的抽象类

  PipedWriter 是向与其它线程共用的管道中写入数据,

   构造函数:

  演示案例】:在硬盘上创建一个文件并写入一些文字数据。

        分析:因为是写操作,所以找到一个专门用于操作文件的Writer子类对象,FileWriter,(后缀名是父亲名,前缀名是该流对象的功能)

5 //创建一个FileWriter对象,该对象一被初始化就必须要明确被操作的文件。 6 //并且该文件会被创建到指定目录下,如果该目录下已有同名文件,将会被覆盖。 9 //调用write方法,将字符串写入流中 11 //调用flush方法,刷新流对象的缓冲中的数据,将数据刷到目的地。 13 //调用close方法,关闭流资源,但关闭之前会刷新一次内部缓冲中的数据。

  上述案例中所有的异常都只是进行了抛出处理,这样是不合理的。所以上述代码并不完善,因为异常没有处理。当我们打开流,读和写,关闭流的时候都会出现异常,异常出现后,后面的代码都不会执行了,因此我们要进行异常处理。

  异常处理的方法:使用try{} catch(){}finally{}语句。try中放入可能出现异常的语句,catch是捕获异常对象,fianlly是一定要执行的代码

  要注意使用try进行异常处理时,将close()方法放在finally中,假设没有放,那么当打开和操作流出现了异常,显然close方法就不会再执行,而导致关闭流失败。

  同时还要注意,关闭多个流时,为了避免一个流关闭失败而导致另一个流也无法关闭的情况,所以要将各个流的关闭分别写在不同的try语句中。

  【演示案例】: IO异常处理的方式:

14 finally {//finally中的代码不管前面try中的代码是否执行成功,finally中的代码总会执行。因此将关闭流的代码放在finally中

  Reader 是所有读取字符流的父类,它是一个抽象类

  FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。

  InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。

  FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。

  read方法():一次读取一个字符,读到文件末尾返回-1.

    注意:该方法返回的是本次读取到的字符的int形式。所以打印时需有将其转化成char类型。

  read(char[] b) 方法:使用缓冲区(关键是缓冲区大小的确定),使用read方法的时候,是将读到的数据装入到字符数组中,然后一次性的操作数组,可以提高效率,流需要读一次就处理一次,因为本次读取的数据会覆盖上次读取的。

    注意:该方法返回的是本次读取到的字符的个数。

   read(char[] b,int off,int len):查看api文档,b显然是一个char类型数组,当做容器来使用。off,是指定从数组的什么位置开始存字节。len,希望读多少个,其实就是把数组的一部分当做流的容器来使用。告诉容器,从什么地方开始装要装多少。

  【演示案例】:从文件中读取内容

8 * 一次读一个字符。 12 // 调用read()方法,该方法返回的是本次读到的字符的整数型,当本次没有读到字符时,返回的是-1 17 * 一次读多个字符。 22 //调用read(char[] ch)方法,将读到的字符都存到ch数组中,该方法返回的是本次读到的字符的个数 23 //当本次没有读到字符时,返回的是-1

  【演示案例】:将C盘的一个文本文档复制到D盘。

   缓冲区的出现提高了对数据的读写效率,其要结合流才可以使用,所以在创建缓冲流对象之前,必须先有流对象。它是在流的基础上对流的功能进行了增强,或者也可以说是对流对象的装饰。

    上述程序中我们为了提高流的使用效率,自定义了字符数组,作为缓冲区.Java其实提供了专门的字符流缓冲来提高效率.BufferedWriterBufferedReader

    BufferedWriterBufferedReader类可以通过减少读写次数来提高输入和输出的速度。它们内部有一个缓冲区,用来提高处理效率。查看API文档,发现可以指定缓冲区的大小。其实内部也是封装了字符数组。

    显然缓冲区输入流和缓冲区输出流要配合使用。首先缓冲区输入流会将读取到的数据读入缓冲区,当缓冲区满时,缓冲输出流会将数据写出。

    注意:当然使用缓冲流来进行提高效率时,对于小文件可能看不到性能in的提升。但是文件稍微大一些的话,就可以看到实质的性能提升了。

        缓冲区的原理:1、使用了底层流对象从具体设备上获取数据,并将数据存储到缓冲区的数组内。

         2、通过缓冲区的read()方法从缓冲区获取具体的字符数据,这样就提高了效率。

         3、如果用read方法读取字符数据,并存储到另一个容器中,直到读取到了换行符时,将另一个容器临时存储的数据转成字符串返回,就形成了readLine()功能。

  【演示案例】:模拟BufferedReader的底层代码

12 //定义一个临时容器,原BufferedReader中封装的是字符数组。

  (1)将文本写入字符输出流(一个数组中),缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

  (2)可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。

  (3)该类在基类的基础上提供了 newLine() 方法,因为并非所有平台都使用换行符 ('\r\n') 来终止各行。因此调用此方法来终止每个输出行,使代码具有跨平台性。

  (5)缓冲 PrintWriter 对文件的输出。如果没有缓冲,则每次调用 print() 方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。

7 //创建一个字符写入流对象 9 //为了提高字符写入流的效率,加入缓冲技术。 10 //将需要提高效率的流对象作为参数提供给缓冲区的构造函数。 19 //关闭缓冲区就是在关闭缓冲区中的流对象 20 //因为真正实现写操作的是FileWriter对象,真正与文件相关联的也是FileWriter对象

  (1)从字符输入流(一个作为缓冲区的数组)中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

  (2)可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

  (3)在基类的基础上提供了readLine()方法(底层调用了read()方法)读取一个文本行,返回该行内容的字符串,不包括任何终止符。如果已到达流末尾,则返回null。

  (5)将缓冲指定文件的输入。如果没有缓冲,则每次调用 read() 或 readLine() 都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。

5 //创建一个字符读取流对象 7 //创建一个字符写入流对象 9 //为了提高字符流的效率,加入缓冲技术。 10 //将需要提高效率的流对象作为参数提供给缓冲区的构造函数。

  它是对缓冲区对象BufferedWriter的功能进行了增强, 是可以跟踪行号的缓冲字符输入流,此类定义了方法setLineNumber()和getLineNumber(),它们分别用于设置和获取当前行号。

  setLineNumber()方法:设置当前行号。默认情况下是从0开始的。

  1. InputStream 是所有的输入字节流的父类,它是一个抽象类
  2. PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。

8 *一次读取一个字节 15 //因为字节流对象是读一个写一个,所以不存在刷新 19 * 一次读取多个字节:方法一 27 //因为字节流对象是读一个写一个,所以不存在刷新 31 * 一次读取多个字节:方法一 38 //因为字节流对象是读一个写一个,所以不存在刷新

  该类为另一个输入流添加一些功能,即缓冲输入以及支持mark和reset方法的能力。在创建BufferedInputStream时会创建一个数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark操作记录输入流中的某个点,reset操作使得在从包含的输入流中获取新字节之前,在此读取自最后一次mark操作后读取的所有字节。

  我们知道字节流对象一般读取到的都是一个字节,那为什么read()方法返回的为什么不是byte而是int呢?这是因为字节流对象读取的音频或图片文件,其中数据在底层都是以二进制的形式存储的,但是当字节流对象读取到的某个字节是(8个1)时,转化成十进制就是-1,这与我们判断结束的条件是相同的(while ((num=bis.read(buf))!=-1){}),此时系统就会认为该文件内容已经读取完而停止继续读取,因而造成数据丢失。为了解决这种情况,就将需要返回的数据转化(提升)为int型数据(从一个字节提升为四个字节),并与上255,之后在返回。那为什么要与上255?这是因为byte型-1转化为int型后还是-1,但是与上255(或0xff)之后,数据大小没有变,且解决了-1的问题。

  -1的问题解决了,那我们又不得不思考另一个问题,我们每次读取时,都读到的是一个字节,但是返回时返回的是四个字节,这样读取到的文件不就成原来文件的四倍了?所以为了解决这个问题,我们在调用写功能时,其底层又进行了强转(向下转型),因此就解决了文件扩大的问题。

  【代码演示】:打印文件中出现次数最多的三个数。

  1. OutputStream 是所有的输出字节流的父类,它是一个抽象类。

b)方法,虽然接收的是int类型参数,但是write 的常规协定是:向输出流写入一个字节。要写入的字节是参数 b 的八个低位。b 的 24 个高位将被忽略。

  调用上述方法往文件里写数据,运行多次就会发现,程序每运行一次,老的内容就会被覆盖掉。那么如何不覆盖已有信息,能够往文件里追加信息呢。查看API文档,发现FileOutputStream类中的构造方法中有一个构造可以实现追加的功能FileOutputStream(File file, boolean

  问题1: 使用缓冲(字节数组)拷贝数据,拷贝后的文件大于源文件的问题.

  测试该方法,拷贝文本文件,仔细观察发现和源文件不太一致。

  打开文件发现拷贝后的文件和拷贝前的源文件不同,拷贝后的文件要比源文件多一些内容问题就在于我们使用的容器,这个容器我们是重复使用的,新的数据会覆盖掉老的数据,显然最后一次读文件的时候,容器并没有装满,出现了新老数据并存的情况。所以最后一次把容器中数据写入到文件中就出现了问题。

  b 是容器,off是从数组的什么位置开始,len是获取的个数,容器用了多少就写出多少。

  该类实现缓冲的输出流。通过设置这种输出流,应用程序就可以将各个字节写入底层输出流中,而不必针对每次字节写入调用底层系统。

  System类包含一些有用的类字短和方法。它不能被实例化。

  (InputStream ) 字段in:“标准”输入流 。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或有主机环境或用户指定的另一个输入源。

  (OutputStream-PrintStream)   字段out:“标准”输出流。此流已打开棒准备接受输出数据。通常,此流对应于显示器输出或者由主机环境或用户指定的另一个输出目标。

  【演示案例】:通过键盘录入数据

   注意:此处只输入了一个字母,却打印出三个数字,说明在windows系统中,换行符是存在的(\r \t)。

   【演示案例】:setIn()和setOut()方法的使用

9 //目的为c盘文件

 1.7 转换流对象(键盘录入,转换编码表)

  它使用指定的charset读取字节并将其解码为字符。

  它使用的字符集可以由名称指定或显示给定,或者可以接受平台默认的字符集。

  【演示案例】通过键盘录入数据(为编码简单,将字节流对象转化为字符流对象)。

5 //获取键盘录入对象 8 //为了提高效率,使用字符缓冲对象。

  1.7.2 OutputStreamWriter是字符流通向字节流的桥梁它使用指定的charset将要写入流中的字符编码成字节。

  【演示案例】:通过控制台显示数据(为编码简单,将字符流对象转化为字节流对象)
6 //获取控制台显示对象 9 //为了提高效率,使用字节缓冲对象。
  【演示案例】将键盘录入的信息存储到指定文件中。
8 //目的为c盘文件

  注意:InputStreamReader可以自定义编码方式,但是它的子类FileReader中不可以自定义,默认为GBK。


【演示案例】
编写异常日志文件。
17 //因为此处可能会出现找不到文件异常所以也要进行扑获 18 //setOut()方法指定输出流,此处指定为C盘的文本文件 20 //printStackTrace()方法的作用是将异常信息输出到指定的输出流中,默认为控制台

  打印字节流,为其他输出流添加了功能,使他们能够方便地打印各种数据值表现形式。与其他输出流不同的是,PrintStream永远不会抛出IOException,异常情况仅设置可通过checkError方法测试的内部标志。另外,PrintStream还支持自动刷新,也意味着PrintStream可通过调用其中的一个print方法,在写入byte数组之后自动调用flush方法,或者也以通过写入一个换行符或字节(‘\n’)。

  注意:PrintStream打印的所有字符都使用平台的默认字符编码转换为字节,在需要写入字符而不是字节的情况下,应使用PrintWiter类。

  PrintStream是OutputStream类的子类,在OutputStream类中write()方法只接受传进来的参数的最低八位,为了不改变数据原样性,于是在它的子类PrintStream中不仅提供了write()写的方法,还提供了println()打印的方法,该方法的好处是可以传进来的数据进行直接操作,可以在打印时保证数据的原样性。

  不用调用fiush就可以自动刷新。输入一行,显示一行。

  打印字符流, 向文本输出流打印对象的格式化表现形式,此类实现了PrintStream中的所有print方法。与PrintStream不同的是,如果启动了自动刷新,则只有在调用println,printf或format方法中的一个方法时,才能完成刷新的操作,而不是每当正好输出换行符才完成,这些方法使用平台自有的行分隔符概念,而不是换行符。

  PrintWriter默认情况下是不带自动刷新功能的,要通过调用flush方法才能实现刷新功能。另外查看Api文档可知,PrintStream还可以通过构造函数来设置自动刷新的功能。(但只有在调用println,printf或format方法时才能自动刷新)

   是InputStream的子类,表示其他输入流的逻辑串联。它从输入流的有序集合开始,并从第一个输入流开始读取,直到到达文件末尾,接着从第二个输入流读取,依次类推,直到到达包含的最后一个输入流的文件末尾为止。

  在这之前一个流只能跟一个文件结合,但有了SequenceInputStream类之后,通过SequenceInputStream可以实现一个流跟多个文件结合。应用实例,将多个文件的内容写到一个文件中。

   构造函数:

   【代码演示】:需要将多个文件(两个以上)合并到一个文件中时。

8 //当要结合的文件大于两个时,使用下面方法 20 //因为PrintWriter的print的方法是接受什么类型就操作什么类型,而此处buff数组是byte类型,因此要将其转为String类型

  【代码演示】:将一个文件切割成多个文件。

 运行之后文档的变化: 由于在存储文档时用Vector效率比较低,所以一般常会选用ArrayList来存储。

  我们一般情况下新new的对象都是在堆内存中存储的,随着程序运行结束,该对象就会被当作垃圾回收掉。但是ObjectStream流对象却可以将堆内存中的创建出来的对象(及其对象内封装的数据)存储到硬盘中,即使程序运行结束,该信息也不会被清除。而将创建出来的对象存储到硬盘上的这一动作称为对象的持久化存储,或者对象的序列化,可串行性。

   序列化原因:序列化以后的对象可以保存到磁盘上,也可以在网络上传输,使得不同的计算机可以共享对象.(序列化的字节序列是平台无关的)

   对象序列化的条件:只有实现了 Serializable 接口的类的对象才可以被序列化。Serializable 接口中没有任何的方法(标记接口),实现该接口的类不需要实现额外的方法。如果对象的属性是对象,属性对应类也必须实现 Serializable接口

  ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中读取(重构)对象。

  只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。

  对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。其他对象的引用(瞬态和静态字段除外)也会导致写入那些对象。可使用引用共享机制对单个对象的多个引用进行编码,这样即可将对象的图形恢复为最初写入它们时的形状。

   【代码演示】:使用文件实现对象的持久存储

23 //将对象写入流中,通过在流中使用文件实现对象的持久存储

   注意:运行完后查看文件中的内容,会发现是一些乱码,这是因为创建出来的对象在往硬盘中存储时要进行序列化,因此在硬盘中存储的都是被序列化后的二进制码,而然用文件查看时,文件不会进行反序列化,而是直接根据编码表进行编译,因此编译出来的都是乱码。

  只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。
  对象的默认序列化机制写入的内容是:对象的类,类签名,以及非瞬态和非静态字段的值。其他对象的引用(瞬态和静态字段除外)也会导致写入那些对象。可使用引用共享机制对单个对象的多个引用进行编码,这样即可将对象的图形恢复为最初写入它们时的形状。

    【代码演示】:将对象从文件中读出来。

   这是因为如果修改过对象的类,那么该对象的序列号就会发生变化,在从文件中读取对象时,因为前后两次序列号不一致就会导致读取失败。

  那如果既想存储对象又想在存储之后还可以修改对象类的代码,那该怎么办??答案是自定义序列号!!在实现Serializable 接口的类的前面添加:public static final long serialVersionUID=23L;

   注意:静态变量不能被序列化,因为静态变量是在方法区中存储的,而只有堆内存中的变量才会被序列化。

  如果变量是非静态的,但是也不想进行序列化该怎么办??答案是用修饰符transient修饰变量!!要注意没有被序列化的变量是不会存储到文件中的,只会存储在堆内存中,并随程序运行完而被清除掉。

  它们的作用是让多线程可以通过管道进行线程间的通讯。在使用管道通信时,必须将PipedOutputStream和PipedInputStream配套使用。使用管道通信时,大致的流程是:我们在线程A中向PipedOutputStream中写入数据,这些数据会自动的发送到与PipedOutputStream对应的PipedInputStream中,进而存储在PipedInputStream的缓冲中;此时,线程B通过读取PipedInputStream中的数据。就可以实现,线程A和线程B的通信。

    管道输入流和管道输出流可以像管道一样对接上。要注意的是需要加入多线程技术,不建议对这两个对象尝试使用单个线程,这样可能死锁线程。因为在单线程中,先执行read,因为read方法是阻塞式的,没有数据的read方法会让线程一直等待,从而发生死锁。

  管道输入流应该连接到管道输出流,管道输出流是管道的发送端。通常,数据由某个线程写入到相应的 PipedOutputStream中,并由其他线程从 PipedInputStream 对象读取。管道输入流包含一个缓冲区,可在缓冲区限定的范围内将读操作和写操作分离开。 如果向连接管道输出流提供数据字节的线程不再存在,则认为该管道已损坏。

5 //不建议对这两个管道流对象尝试使用单个线程,这样可能死锁线程,所以此处运用多线程

   分析运行过程:假设两个线程开启后,Read线程先抢到执行权,当Read线程执行到PipedIntputStream流的read方法时,因为PipedInputStream流中没有数据,所以Read线程因read方法读取数据失败而被阻塞,然后执行权被Write线程抢占,并通过PipedOutputStream的write方法将数据内容写到PipedInputStream流中,当Read线程重新抢到执行权时,就可继续执行read方法。

我要回帖

更多关于 1996年2月5日八字 的文章

 

随机推荐