`
guoyunsky
  • 浏览: 845044 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
3d3a22a0-f00f-3227-8d03-d2bbe672af75
Heritrix源码分析
浏览量:204461
Group-logo
SQL的MapReduce...
浏览量:0
社区版块
存档分类
最新评论

Java多线程环境下如何高效安全处理数据(输入输出流、文件、网络等)(二)

    博客分类:
  • java
阅读更多

       本博客属原创文章,欢迎转载!转载请务必注明出处:http://guoyunsky.iteye.com/blog/868043

 

         由于不想让博客太难看,所以写到二.这里也会循序渐进,一步步走入所谓的高效和安全.

       上一篇,介绍了思路、设计。博客地址:http://guoyunsky.iteye.com/blog/867469 同时写了个MyOutputStream,用于读取输入流(如IO、网络),但恐怕输入流过大,或者多线程并发读取的时候导致总的内存占用过大.所以采用缓存+文件存放形式。缓存固定一个大小,这样可以控制内存,同时可以重复利用.超过缓存的数据写入到磁盘,避免内存溢出。但如此保存的数据又要读取出来处理,那就又需要一个读取类.将缓存和硬盘中的数据都读出。有人可能会说,怎么会这么麻烦?有这种需求吗?就比如发表博客,网站需要过滤敏感词.那么就需要多个线程读取博客,然后过滤关键字后输出到MyOuputStream.之后还需要什么处理,但就要获取这些数据.于是有了下面一个类,可以以流的形式读取缓存和磁盘中的数据.先贴上代码:

 

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;

public class ReuseInputStream extends InputStream {
    private InputStream diskStream; // 硬盘数据
    private long position;          // 当前位置
    private long size;              // 数据大小
    private byte[] buffer;          // 缓存
    
    
    
    public ReuseInputStream(long size, byte[] buffer,String backedFileName) throws FileNotFoundException {
        super();
        this.size = size;
        this.buffer = buffer;
        
        if(size>buffer.length){
            File backedFile=new File(backedFileName);
            //RandomAccessFile raf=new RandomAccessFile(backedFile,"r"); // 先埋个伏笔,还有改进之处
            diskStream=new FileInputStream(backedFile);
        }
    }
    
    @Override
    public int read() throws IOException {
        if(position==size){ // 已经满了
            return -1;
        }
        
        if(position<buffer.length){    // 先从缓存中读
           int c=buffer[(int)position]& 0xFF; 
           position++;
           return c;
        }
        
        // 缓存中已经读取完毕,从文件中读取
        int c=diskStream.read();
        if(c>=0){   // 确保文件中也还有数据
            position++;
        }
        return c;
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        if(position==size){  // 已经满了
            return -1;
        }
        
        if(position<buffer.length){ // 先从缓存中读取,但缓存读完了,不会从硬盘中读取,而是直接返回
            int toCopy=(int)Math.max(size-position, Math.min(len, buffer.length-position)); // 计算要从缓存中读取的字节数
            if(toCopy>0){
                System.arraycopy(buffer, (int)position, b, off, len);
                position+=toCopy;
            }
            return toCopy;
        }
        
        int c=diskStream.read(b, off, len); // 从磁盘中读取
        if(c>0){
            position+=c;
        }
        return c;
        
    }

    @Override
    public void close() throws IOException {
        super.close();
        if(diskStream!=null){
            diskStream.close();
        }
    }
    
    // 获得数据大小
    public long getSize() {
        return size;
    }
    
    // 剩下的数据长度
    public long getRemain(){
        return size-position;
    }
    // 获得当前位置
    public long getPosition() {
        return position;
    }
    
    // 获得缓存数据
    public byte[] getBuffer() {
        return buffer;
    }
    
}

 

      这个类得提供给MyOutputStream,让它可以返回它里面的数据,于是修改MyOutputStream。这里省略前面的代码,同时可以看测试:

 

package streamUnderThreads;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

public class MyOutputStream extends OutputStream {
    private boolean isOpen;         // 是否已经打开
    private long size;              // 数据总大小
    private String backedFileName;  // 超出缓存,要写入到的文件名
    private OutputStream diskStream;// 超出缓存,写入到文件的OutputStream
    private byte[] buffer;          // 缓存
    private long position;          // 当前位置
    private boolean recording;      // 是否记录数据中
    
    //省略...
       
    // 获得数据流
    public ReuseInputStream getReuseInputStream() throws IOException{
        return new ReuseInputStream(size,buffer,backedFileName);
    }
     
    public static void main(String[] args) {
        String dir=new File("").getAbsolutePath().concat(File.separator);
        String fileMemory=dir.concat("fileMemory.txt");
        String fileDisk=dir.concat("fileDisk.txt");
        int bufferSize=5;
        MyOutputStream mosMemory=null;
        MyOutputStream mosDisk=null;
        try {
            mosMemory=new MyOutputStream(bufferSize,fileMemory);
            mosMemory.open();
            
            mosDisk=new MyOutputStream(bufferSize,fileDisk);
            mosDisk.open();
            
            for(int i=0;i<100;i++){
                if(i<bufferSize){
                    mosMemory.write(i);
                }
                mosDisk.write(i);
            }
            
            mosMemory.close();
            mosDisk.close();
            
            System.out.println("mosMemory length:"+mosMemory.getSize());
            System.out.println("mosDisk length:"+mosDisk.getSize());
            
            // 返回数据流
            ReuseInputStream ris=mosDisk.getReuseInputStream();
            StringBuilder sb=new StringBuilder();
            int c;
            while((c=ris.read())!=-1){
                sb.append(c);
            }
            System.out.println(sb.toString());
            
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }finally{
            
        }
    }

}

 

    以上只是以流的形式返回,但有时就是有需求,要将整个内容都返回放入内存中,如此内存还是有要爆的风险.那又该怎么处理?再开篇博客,请看三...

 

更多技术文章、感悟、分享、勾搭,请用微信扫描:

分享到:
评论
4 楼 guoyunsky 2011-01-17  
lzg406 写道
LZ这两篇文章不错,不过还是没涉及多线程


最近有点忙,等有时间再跟进!
3 楼 lzg406 2011-01-13  
LZ这两篇文章不错,不过还是没涉及多线程
2 楼 lwf2510 2011-01-12  
楼主,多写点注释,让我们看更明白点啊。辛苦了,
1 楼 泛舟天下 2011-01-12  
看了LZ的两篇博文,总体感觉文字性的原理描述比较少

相关推荐

    Java输入输出流以及线程讲解

    Java输入输出流(I/O流)是Java编程中不可或缺的一部分,它允许程序处理数据的读取、写入和传输。Java I/O系统基于流的概念,流可以被视为数据的有序序列,既可以是从源(如文件、网络连接)读取数据的输入流,也...

    IO和线程java输入输出 多线程

    输入/输出处理数据的传输,而多线程则涉及程序的并发执行。 首先,让我们深入理解Java的IO系统。Java.IO包包含了大量用于处理输入和输出操作的类和接口。输入流(InputStream)和输出流(OutputStream)是这个包的...

    JAVA输入输出流实验报告

    Java中的输入输出流是程序与外部数据...总之,Java的输入输出流是其强大的特性之一,为开发者提供了灵活且高效的处理数据输入输出的能力。通过不断的实践和学习,我们可以掌握更多的IO技巧,更好地应对各种实际问题。

    java输入输出流,电子课件

    Java输入输出流是Java编程中不可或缺的部分,它用于应用程序与外部设备之间进行数据交换,比如磁盘、网络、键盘和显示器。I/O流是Java中处理输入和输出的基础框架,它提供了一种抽象的方式来处理不同类型的输入源和...

    java实现多线程文件传输

    5. **I/O流**:在Java中,`InputStream`和`OutputStream`是用于读写文件的基础类,多线程传输时,每个线程可以拥有自己的输入/输出流实例,分别处理文件的一部分。 6. **异常处理**:多线程环境下,需要确保每个...

    java中的标准输入输出流

    Java提供了丰富的I/O处理机制,包括标准输入输出流、字节流、字符流等多种方式来处理数据的读取和写入。标准输入输出流是Java中非常基础且重要的组成部分。 **1.1 标准输入输出流简介** - **System.out**: 是一个`...

    文件管理和输入输出流.rar

    "文件管理和输入输出流"这个主题涵盖了Java、C语言、C++、C#以及JSP等多种编程语言中的相关技术,这些技术使得程序员能够有效地读取、写入和处理文件数据。 首先,我们来探讨文件管理。文件管理主要包括创建、打开...

    java多线程文件传输(基于swing)

    Java多线程文件传输是一个复杂而实用的编程概念,它结合了Java的Socket编程和Swing GUI库,用于实现高效的数据交换。在这个项目中,开发者创建了一个基于Socket的多线程文件传输系统,允许用户通过图形化用户界面...

    java基础代码_java_输入输出流_接口_多线程_异常_

    在Java中,输入输出流是一组类和接口,用于读取和写入数据到不同的源和目标,如文件、网络连接或内存。Java的IO流分为字节流和字符流两大类,字节流处理原始的8位字节数据,而字符流则处理Unicode字符。基本的输入流...

    java输入输出流的两种写法

    Java 输入输出流是Java编程语言中处理数据传输的基础机制,主要负责程序与外部资源(如文件、网络连接等)之间的数据交互。Java 提供了多种类型的流,它们分为两大类:字节流(处理单个字节的数据)和字符流(处理...

    java多线程URL方式下载单个大文件

    然后,我们引入`java.nio`包,这个包提供了非阻塞I/O操作,使得在多线程环境下处理数据更高效。特别是`java.nio.channels.Channels`和`java.nio.file.Files`类,它们可以帮助我们将输入流转换为通道,并将数据写入到...

    Java语言与面向对象程序设计第16讲(异常处理,多线程和流式输入输出与文件处理)

    总的来说,Java的异常处理、多线程和流式输入输出与文件处理是编程中重要的概念,理解并熟练运用它们能帮助开发者编写更健壮、安全和高效的代码。对于初学者而言,通过阅读详细的教程和实践练习,可以逐步掌握这些...

    java输入输出流的代码示例

    Java输入输出流是Java编程语言中的核心概念,用于在程序之间、程序与文件系统、网络连接等不同数据源之间传输数据。在这个主题中,我们将深入探讨Java输入输出流的使用,通过具体的代码示例帮助你理解和掌握这个关键...

    java多线程下载工具,仿照迅雷

    3. **输入/输出流**:Java的IO流是处理数据输入和输出的基础,下载工具中通常会用到`InputStream`(用于读取服务器的数据)和`OutputStream`(用于将数据写入本地文件)。例如,我们可以使用`BufferedInputStream`和...

    java多线程网络传输文件(非同步)

    ### Java多线程网络传输文件(非同步) #### 概述 在现代软件开发中,尤其是在涉及大量数据传输的应用场景下,高效的文件传输方案尤为重要。Java作为一种广泛应用的编程语言,提供了丰富的工具和技术来实现高性能...

    Java学习资料(内含基本语法、异常处理、Applet编程、GUI、线程、输入输出流等)

    综上所述,这份Java学习资料涵盖了从基础到高级的多个主题,包括基本语法、面向对象编程、异常处理、Applet、GUI设计、多线程以及输入输出流。对于想要系统学习Java的初学者,这是一份非常全面且深入的学习资源。...

    WHUT-java多线程实验-第三周-文件上传和下载.zip

    总的来说,这个实验将教会你如何在Java多线程环境中实现高效、稳定的文件上传和下载功能,这是一项对任何开发人员来说都非常实用的技能,尤其是在构建高性能的Web应用或后台服务时。通过实践和理解这些概念,你将...

    java多线程下载源代码

    综上所述,Java多线程下载涉及到多线程编程、网络通信、文件操作、并发控制等多个核心Java技术,通过合理设计和优化,可以显著提升下载大文件的效率。在实际开发中,还需要考虑如何将这些概念应用于具体的项目需求,...

    输入输出流及线程资料

    在Java编程语言中,输入输出流(Input/Output Stream)是处理数据传输的核心概念,而线程则是实现并发处理和程序高效运行的关键机制。这两者在构建高效、响应迅速的应用程序时都扮演着至关重要的角色。 输入输出流...

Global site tag (gtag.js) - Google Analytics