------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------
十一、递归
概述
就是函数自身调用自身
当一个功能被重复使用,并且每次使用时参与运算的结果和上一次运算有关,这时候就可以用递归来解决问题
注意!
一定要定义递归的条件
递归的次数不要太多,否则容易出现StackOverflowError栈内存溢出错误
代码示例列出指定目录下所有的文件和文件夹(带层次)
import java.io.File;
public class FileListDemo{
public static void main(String[] args){
//关联指定路径
File dir = new File("D:\\Java\\jdk1.6.0_02\\include" );
//列出目录下所有文件或者文件夹
listAll(dir,0);
}
public static void listAll(File dir, int level) {
//有层次的输出
System.out.println(getSpace(level) + "dir:" + dir.getAbsolutePath());
//获取指定目录下当前的所有文件夹或者文件对象
level++;
File[] files = dir.listFiles();
for (int x = 0; x < files.length; x++){
//如果目录下还有目录继续调用listAll函数
if (files[x].isDirectory()){
listAll(files[x],level);
}
System.out.println(getSpace(level) + "file:" + files[x].getAbsolutePath());
}
}
//带层次的列表
private static String getSpace( int level){
StringBuilder sb = new StringBuilder();
sb.append( "|--" );
for (int x = 0; x < level; x++){
sb.append( "|-- " );
}
return sb.toString();
}
}
需求:利用递归求1到10的和
public class SumDemo {
public static void(String args[]) {
int sum = getSun(10);
System.out.println(sum);
}
public static int getSum(int num) {
if (num == 1);
return 1;
return num + getSum(num - 1);//利用递归,不断使用这个函数完成10到1的求和
}
}
import java.io.File;
public class RemoveDirTest{
public static void main(String[] args){
//指定要删除的目录
File dir = new File("d:\\demo" );
//删除目录
removeDir(dir);
}
public static void removeDir(File dir){
//列出所有文件和文件夹
File[] files = dir.listFiles();
//遍历所有文件夹和文件夹
for(File file : files){
//检查是否是文件夹
if(file.isDirectory()){
//如果是继续调用remove函数删除文件夹中内容
removeDir(file);
}
else{
System.out.println(file + ":" + file.delete());//删除文件
}
}
System.out.println(dir + ":" + dir.delete());//删除目录
}
}
十二、Properties类
概述
一个可以将键值进行持久化存储的对象。是Map--Hashtable的子类。
用于属性配置文件,键和值都是字符串型
特点
可以持续化存储数据。
键值都是字符串
一般用于配置文件
常用方法
1、设置
Object setProperty(String key,String value); //设置键和值,调用Hashtable的方法put
2、获取
String getProperty(String key); //指定key搜索value
Set<String> stringPropertyName();//去除所有元素,存入Set集合,返回的是键的集合
需求:获取一个应用程序运行的次数,如果超过5次,给出使用次数已到请注册的提示,并不要再运行程序。
/*思路:很容易想到用一个计数器来记录使用的次数,但是一旦关闭程序计数器就会被初始化,
因此要建立一个配置文件,用于记录使用次数。该配置文件使用键值对的形式储存,
键值对是map集合,数据以文件形式储存使用io流,IO+map=Properties
*/
import java.io.*;
import java.util.Properties;
public class PropertiesTest{
public static void main(String[] args) throws IOException {
getAppCount();
}
public static void getAppCount() throws IOException {
//将配置文件封装成File对象
File confile = new File("count.properties" );
//如果不存在 新建一个配置文件
if(!confile.exists()) {
confile.createNewFile();
}
FileInputStream fis = new FileInputStream(confile);
Properties prop = new Properties();
//将读取流和指定文件相关联,并读取一行数据,将键值储存到properties集合中
prop.load(fis);
//从集合中通过键获取次数
String value = prop.getProperty( "time");
//定义计数器,记录获取到的次数
int count = 0;
if(value != null) {
count = Integer.parseInt(value);
if(count >= 5){
throw new RuntimeException("使用次数已到,请注册,给钱!" );
}
}
count++;
//将改变后的次数重新存储到集合中。
prop.setProperty( "time",count + "" );
FileOutputStream fos = new FileOutputStream(confile);
prop.store(fos, "");
fos.close();
fis.close();
}
}
十三、打印流
概述
PrintWriter与PrintStream,可以直接操作输入流和文件
提供了更多功能,比如打印方法。可以直接打印任意类型的数据
他有一个自动刷新机制,创建该对象,指定参数,对于指定方法可以自动刷新
它使用的苯基默认的字符编码
该流的print方法不抛出IOException
字节打打印流:PrintStream
构造函数可以接收的参数类型:
File对象:File;
字符串路径:String;
字节输出流:OutputStream
字符串打印流:PrintWriter
构造方法中可接受的参数类型
File对象:File
字符串路径:String
字节输出流:OutputStream
字符输出流:Writer
代码示例
import java.io.BufferedReader;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;
//写入到out.txt文件中
public class PrintWriterDemo{
public static void main(String[] args) throws IOException {
//一行录入
BufferedReader bufr = new BufferedReader(new InputStreamReader(System.in));
//PrintWriter构造函数的第二个参数设置为true,表示自动刷新,所以不用flush
PrintWriter out = new PrintWriter(new FileWriter("out.txt" ),true);
String line = null;
while((line = bufr.readLine()) != null){
//读取到over结束
if("over" .equals(line))
break;
out.println(line.toUpperCase());
}
out.close();
bufr.close();
}
}
十三、序列流
概述
作用就是将多个读取流合并成一个读取流。SequenceInputStream实现数据合并
构造函数
SequenceInputStream(Enumeration<?extends FileInputStream> e)
合并原理
多个读取流对应一个输出流
切割原理
一个读取流对应多个输出流
合并流代码示例
import java.io.*;
import java.util.*;
class SequenceDemo {
public static void main(String[] args) throws IOException {
Vector<FileInputStream> v=new Vector<FileInputStream>();//创建集合对象
//将流对象添加进集合
v.add(new FileInputStream("e:\\javaLX\\1.txt"));
v.add(new FileInputStream("e:\\javaLX\\2.txt"));
v.add(new FileInputStream("e:\\javaLX\\3.txt"));
//创建Enumeration对象,将集合元素加入
Enumeration<FileInputStream> en=v.elements();
//创建SequenceInputStream对象,合并流对象
SequenceInputStream sis=new SequenceInputStream(en);
FileOutputStream fos=new FileOutputStream("e:\\javaLX\\4.txt");
byte[] buf=new byte[1024];
int len=0;
while((len=sis.read(buf))!=-1) {
fos.write(buf,0,len);
}
fos.close();
sis.close();
}
}
切割代码示例
import java.io.*;
import java.util.*;
class SplitFile {
public static void main(String[] args) throws IOException {
spliFile();
}
public static void spliFile() throws IOException {
FileInputStream fis=new FileInputStream("e:\\javaLX\\1.gif");
FileOutputStream fos=null;
byte[] buf=new byte[1024*1024];//碎片文件大小引用
int len=0;
int count=1;
while((len=fis.read(buf))!=-1) {
//每循环一次都创建一个格式为part的文件
fos=new FileOutputStream("e:\\javaLX\\"+(count++)+".part");
fos.write(buf,0,len);
fos.close();
}
fis.close();
}
}
十四、RandomAccessFile
概述
随机访问文件,自身具备读写方法
通过skipBytes(int x),seek(int x)等方法来达到随机访问
特点:
1. 该对象即能读,又能写。
2. 该对象内部维护了一个byte数组,并通过指针可以操作数组中的元素。
3. 可以通过getFilePointer方法获取指针的位置,和通过seek方法设置指针的位置。
4. 其实该对象就是将字节输入流和输出流进行了封装。
5. 该对象的源或者目的只能是文件。通过构造函数就可以看出。
注意!
实现随机访问,数据最好有规律
十五、管道流
概述
PipedInputStreamt和PipedOutputStream:输入输出可以直接进行连接,通过结合线程使用。
代码示例
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
public class PipedStream{
public static void main(String[] args) throws Exception {
PipedInputStream input = new PipedInputStream();
PipedOutputStream output = new PipedOutputStream();
input.connect(output);//链接管道读取流和管道写入流
//加入多线程技术,因为单线程,先执行read,会发生死锁,
//因为read方法是阻塞式的,没有数据read方法会让线程等待
new Thread(new Input(input)).start();
new Thread(new Output(output)).start();
}
}
class Input implements Runnable{
private PipedInputStream in;
Input(PipedInputStream in){
this.in = in;
}
public void run(){
try{
byte[] buf = new byte[1024];
int len = in.read(buf);
String s = new String(buf,0,len);
System.out.println( "s=" + s);
in.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
class Output implements Runnable{
private PipedOutputStream out;
Output(PipedOutputStream out){
this.out = out;
}
public void run(){
try{
out.write( "hi,管道来了!" .getBytes());
out.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
概述
计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。
将各个国家的文字用数字来表示,并一一对应,形成一张表,这就是编码表。
常见的编码表
ASCII:美国标准信息交换码,用一个字节的7位可以表示。
ISO8859-1:拉丁码表。欧洲码表,用一个字节的8位表示。
GB2312:中国的中文编码表。
GBK:中国的中文编码表升级,融合了更多的中文文字符号。
Unicode:国际标准码,融合了多种文字。
所有文字都用两个字节来表示,Java语言使用的就是unicode
UTF-8:最多用三个字节来表示一个字符。
代码示例
public static void main(String[] args) throws IOException{
//字符串-->字节数组:编码
//字符数组-->字符串:解码
String str = "您好";
//编码
byte[] buf1 = str.getBytes("GBK" );
printBytes(buf1);
byte[] buf2 = str.getBytes("UTF-8" );
printBytes(buf2);
//解码,GBK是默认编码表不需要注释
String s1 = new String(buf1);
System.out.println( "s1 = " + s1);
String s2 = new String(buf2,"UTF-8" );
System.out.println( "s2 = " + s2);
}
private static void printBytes(byte[] buf){
for(byte b : buf){
System.out.print(b + " ");
}
System.out.println();
}
}
练习
需求:编写函数,从一个字符串中按字节数截取一部分,但不能截取出半个中文(GBK码表),例如:从“HM程序员”中截取2个字节是“HM”,截取4个则是“HM程”,截取3个
字节也要是"HM"而不要出现半个中文
<span style="font-size:10px;"></span><pre name="code" class="java">import java.util.*;
import java.io.*;
public class Test {
public static void main(String args[])
throws UnsupportedEncodingException {
//从键盘录入字符串和要截取的字符串长度
String str = null;
int length = 0;
Scanner sc = new Scanner(System.in);
System.out.println("请输入字符串");
str = sc.nextLine();
System.out.println("请输入要截取的字符串长度");
//将输入信息的下一个标记扫描为一个 int。
length = sc.nextInt();
sc.close();
System.out.println("截取后的结果是"+cutStringByByte(str,length));
}
private static String cutStringByByte(String str, int length)
throws UnsupportedEncodingException {
//将字符串转换为字符数组
byte[] buf=str.getBytes("gbk");
int count=0;
//length-1为最后一个角标 ,判断最后一个字节是否是中文
for(int x=length-1;x>0;x--){
//gbk编码的值两个字节值一般都为负,记录连续的负数个数,如果为奇数,则舍弃
//如果字节负数,说明是汉字
if(buf[x]<0) {
//记录负数个数
count++;
}
else {
break;
}
}
//如果截取的数,能整除2,说明是汉字的后半部分,不需要截取
if(count%2==0) {
return new String(buf,0,length,"gbk");
}
else {
//如果截取的数,不能整除2,说明是汉字的前半部分,需要截取
return new String(buf,0,length-1,"gbk");
}
}
}