精华内容
下载资源
问答
  • java多线程读写文件之文件锁
    2021-02-12 16:53:49

    文件修改始终是一件很麻烦也很出错的行为。多线程读写文件更是会加大文件内容混乱的概率,这时,必定要保证在某一个时刻,只有一个线程在对文件进行读写操做。那么其余访问文件的线程该怎么办呢?就像去ATM取钱同样,当ATM正在被使用时,那么其余想要使用ATM的人只能等待知道ATM能使用。java

    读写文件也同样,当一个线程得到文件时,给予这个线程文件锁。只有拥有文件锁的线程才能操做文件,其余线程就须要一直等待,直到得到文件锁。多线程

    下面的代码实现了以下的功能:app

    读取文件内容;

    对内容进行修改;

    将修改后的内容写入文件;

    替换掉原有的内容。

    须要注意的地方有:dom

    文件锁定;

    替换文件内容时文件指针的位置;

    新内容写入文件时,会覆盖掉原有的内容。注意是覆盖。过新的内容比原有内容少,那么只会覆盖掉新内容长度的字符。例如原有内容是:ab,新写入的内容是:1,些动做完成只够,文件的内容是:1b。所以这里要注意选择。

    private void addConfig(String configStr){

    File file = new File(CONFIG_FILE);

    RandomAccessFile write = null;

    FileChannel channel = null;

    FileLock lock = null;

    try {

    write = new RandomAccessFile(file, "rws");

    channel = write.getChannel();

    while(true){

    try {

    lock = channel.lock();//尝试得到文件锁,若文件正在被使用,则一直等待

    break;

    } catch (Exception e) {

    System.out.println("write::: some other thread is holding the file...");

    }

    }

    String content = readConfig(write, configStr);

    write.seek(0);//替换原有文件内容

    write.write(content.getBytes());

    lock.release();

    channel.close();

    write.close();

    } catch (IOException e) {

    throw new FileNotExistException("config file is not exist").addScene("config", CONFIG_FILE);

    }

    }

    代码中的

    readConfig(RandomAccessFile write , String configStr)方法会读取文件内容,并将字符串

    configStr插入其中。其实现以下:

    private String readConfig(RandomAccessFile reader, String configStr) {

    StringBuffer sb = new StringBuffer();

    try {

    if (reader != null) {

    String txt = new String();

    while ((txt = reader.readLine()) != null) {

    sb.append(txt + "\n");

    if (" \"collect_items\":[".equals(txt)) {

    sb.append(configStr);

    }

    }

    } else {

    throw new FileIOException("reader is null...").addScene(

    "reader", reader);

    }

    return sb.toString();

    } catch (IOException e) {

    throw new FileIOException("exception when read content").addScene(

    "config", CONFIG_FILE);

    }

    }

    由于读写都是用的同一个

    RandomAccessFile,因此当读取动做执行完成以后,此时的文件指针已经在文件内容末尾了。要替换掉原有的内容就须要将指针移到文件首部。须要

    write.seek(0);这个方法来实现。此时写入的内容就会覆盖掉原来文件中的内容。

    不足:

    在获取文件锁的地方:

    while(true){

    try {

    lock = channel.lock();

    break;

    } catch (Exception e) {

    System.out.println("write::: some other thread is holding the file...");

    }

    }

    不论怎么看都以为有点别扭,你是否有好的解决方案呢?

    更多相关内容
  • 主要介绍了java多线程读写文件示例,需要的朋友可以参考下
  • 今天小编就为大家分享一篇对Python多线程读写文件加锁的实例详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 主要为大家详细介绍了java多线程读取多个文件的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Java多线程读取文件

    2020-12-22 21:24:55
    前言  是五一假期第,按理应该是快乐玩耍的日子,...  为了充分利用多线程读取,需要把文件划分成多个区域,供每个线程读取。那么需要有一个算法来计算出每个线程读取的开始位置和结束位置。那么首先根据配置的线程
  • 在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址。如果有知情者,烦请帖出地址,我在此文上加入引用...

    在写之前先声明,本文是基于之前在博客园网站上检索到的一份JAVA多线程读写文件的示例,我在写自己的程序时是在那位作者写的基础上做了改良,但已不记得原文的地址。如果有知情者,烦请帖出地址,我在此文上加入引用或转载。

    本程序是基于这么一种考虑,某系统后台有个将近2G大小的日志文件,你用任何编辑器去打开它,都将会很困难。针对这样的大文件解析处理,解决方案是使用多个线程,分割读取指定的大文件。获取我们所需要的信息。不多说,上代码了,有注释可以帮助理解。

    Java代码  5dcc728ba911b6562957664715830fca.png

    package com.thread.multipl.mysolution;

    import java.io.IOException;

    import java.io.RandomAccessFile;

    import java.util.concurrent.CountDownLatch;

    /**

    * 这个线程用来读取文件,当获取到指定关键字时,在指定的对象加1

    * @author 刘峰管理2

    *

    */

    public class ReadThread extends Thread{

    //定义字节数组(取水的竹筒)的长度

    private final int BUFF_LEN = 256;

    //定义读取的起始点

    private long start;

    //定义读取的结束点

    private long end;

    //将读取到的字节输出到raf中  randomAccessFile可以理解为文件流,即文件中提取指定的一部分的包装对象

    private RandomAccessFile raf;

    //线程中需要指定的关键字

    private String keywords;

    //此线程读到关键字的次数

    private int curCount = 0;

    /**

    * jdk1.5开始加入的类,是个多线程辅助类

    * 用于多线程开始前统一执行操作或者多线程执行完成后调用主线程执行相应操作的类

    */

    private CountDownLatch doneSignal;

    public ReadThread(long start, long end, RandomAccessFile raf,String keywords,CountDownLatch doneSignal){

    this.start = start;

    this.end = end;

    this.raf  = raf;

    this.keywords = keywords;

    this.doneSignal = doneSignal;

    }

    public void run(){

    try {

    raf.seek(start);

    //本线程负责读取文件的大小

    long contentLen = end - start;

    //定义最多需要读取几次就可以完成本线程的读取

    long times = contentLen / BUFF_LEN+1;

    System.out.println(this.toString() + " 需要读的次数:"+times);

    byte[] buff = new byte[BUFF_LEN];

    int hasRead = 0;

    String result = null;

    for (int i = 0; i 

    //之前SEEK指定了起始位置,这里读入指定字节组长度的内容,read方法返回的是下一个开始读的position

    hasRead = raf.read(buff);

    //如果读取的字节数小于0,则退出循环! (到了字节数组的末尾)

    if (hasRead 

    break;

    }

    result = new String(buff,"gb2312");

    ///             System.out.println(result);

    int count = this.getCountByKeywords(result, keywords);

    if(count > 0){

    this.curCount += count;

    }

    }

    KeyWordsCount kc = KeyWordsCount.getCountObject();

    kc.addCount(this.curCount);

    doneSignal.countDown();//current thread finished! noted by latch object!

    } catch (IOException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    }

    public long getStart() {

    return start;

    }

    public void setStart(long start) {

    this.start = start;

    }

    public long getEnd() {

    return end;

    }

    public void setEnd(long end) {

    this.end = end;

    }

    public RandomAccessFile getRaf() {

    return raf;

    }

    public void setRaf(RandomAccessFile raf) {

    this.raf = raf;

    }

    public int getCountByKeywords(String statement,String key){

    return statement.split(key).length-1;

    }

    public int getCurCount() {

    return curCount;

    }

    public void setCurCount(int curCount) {

    this.curCount = curCount;

    }

    public CountDownLatch getDoneSignal() {

    return doneSignal;

    }

    public void setDoneSignal(CountDownLatch doneSignal) {

    this.doneSignal = doneSignal;

    }

    }

    Java代码  5dcc728ba911b6562957664715830fca.png

    package com.thread.multipl.mysolution;

    import java.io.File;

    import java.io.RandomAccessFile;

    import java.util.concurrent.CountDownLatch;

    public class MultiReadTest {

    /**

    * 多线程读取文件测试

    * @param args

    */

    public static void main(String[] args) {

    // TODO Auto-generated method stub

    final int DOWN_THREAD_NUM = 10;//起10个线程去读取指定文件

    final String OUT_FILE_NAME = "d:\\倚天屠龙记.txt";

    final String keywords = "无忌";

    //jdk1.5线程辅助类,让主线程等待所有子线程执行完毕后使用的类,

    //另外一个解决方案:自己写定时器,个人建议用这个类

    CountDownLatch doneSignal = new CountDownLatch(DOWN_THREAD_NUM);

    RandomAccessFile[] outArr = new RandomAccessFile[DOWN_THREAD_NUM];

    try{

    long length = new File(OUT_FILE_NAME).length();

    System.out.println("文件总长度:"+length+"字节");

    //每线程应该读取的字节数

    long numPerThred = length / DOWN_THREAD_NUM;

    System.out.println("每个线程读取的字节数:"+numPerThred+"字节");

    //整个文件整除后剩下的余数

    long left = length % DOWN_THREAD_NUM;

    for (int i = 0; i 

    //为每个线程打开一个输入流、一个RandomAccessFile对象,

    //让每个线程分别负责读取文件的不同部分

    outArr[i] = new RandomAccessFile(OUT_FILE_NAME, "rw");

    if (i != 0) {

    //

    //                    isArr[i] = new FileInputStream("d:/勇敢的心.rmvb");

    //以指定输出文件创建多个RandomAccessFile对象

    }

    if (i == DOWN_THREAD_NUM - 1) {

    //                    //最后一个线程读取指定numPerThred+left个字节

    //                  System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred+ left)+"的位置");

    new ReadThread(i * numPerThred, (i + 1) * numPerThred

    + left, outArr[i],keywords,doneSignal).start();

    } else {

    //每个线程负责读取一定的numPerThred个字节

    //                  System.out.println("第"+i+"个线程读取从"+i * numPerThred+"到"+((i + 1) * numPerThred)+"的位置");

    new ReadThread(i * numPerThred, (i + 1) * numPerThred,

    outArr[i],keywords,doneSignal).start();

    }

    }

    }catch(Exception e){

    e.printStackTrace();

    }

    //      finally{

    //

    //      }

    //确认所有线程任务完成,开始执行主线程的操作

    try {

    doneSignal.await();

    } catch (InterruptedException e) {

    // TODO Auto-generated catch block

    e.printStackTrace();

    }

    //这里需要做个判断,所有做read工作线程全部执行完。

    KeyWordsCount k = KeyWordsCount.getCountObject();

    //      Map resultMap = k.getMap();

    System.out.println("指定关键字出现的次数:"+k.getCount());

    }

    }

    Java代码  5dcc728ba911b6562957664715830fca.png

    package com.thread.multipl.mysolution;

    /**

    * 统计关键字的对象

    * @author 刘峰管理2

    *

    */

    public class KeyWordsCount {

    private static KeyWordsCount kc;

    private int count = 0;

    private KeyWordsCount(){

    }

    public static synchronized KeyWordsCount getCountObject(){

    if(kc == null){

    kc = new KeyWordsCount();

    }

    return kc;

    }

    public synchronized void  addCount(int count){

    System.out.println("增加次数:"+count);

    this.count += count;

    }

    public int getCount() {

    return count;

    }

    public void setCount(int count) {

    this.count = count;

    }

    }

    运行结果如下:

    引用

    文件总长度:2012606字节

    每个线程读取的字节数:201260字节

    Thread[Thread-0,5,main] 需要读的次数:787

    Thread[Thread-1,5,main] 需要读的次数:787

    Thread[Thread-2,5,main] 需要读的次数:787

    Thread[Thread-3,5,main] 需要读的次数:787

    Thread[Thread-4,5,main] 需要读的次数:787

    Thread[Thread-5,5,main] 需要读的次数:787

    Thread[Thread-6,5,main] 需要读的次数:787

    Thread[Thread-7,5,main] 需要读的次数:787

    Thread[Thread-8,5,main] 需要读的次数:787

    Thread[Thread-9,5,main] 需要读的次数:787

    增加次数:0

    增加次数:146

    增加次数:432

    增加次数:539

    增加次数:587

    增加次数:717

    增加次数:631

    增加次数:467

    增加次数:665

    增加次数:538

    指定关键字出现的次数:4722

    我用10个线程去解析金庸大师写的《倚天屠龙记》,“无忌”这个词在这部小说中一共出现了4722次。实在找不到再大一些的文件了。倚天屠龙记.txt的大小4M出头。

    关于CountDownLatch类的作用说明:

    在API文档中,已经说明是一个辅助类。用于控制主线程与子线程之间切换的一个工具类。用法网上去搜下。ITEYE里也有人讨论过。我在这里使用它解决这样的问题:在确保10个线程都完成文件的解析工作后,系统调用主线程做剩下该做的事情,即:输出“出现的次数”。不确保这点的话,会导致执行完第4个线程,后面的线程还没开始,系统已经做最后一步输出统计结果,这样就达不到我们要的效果。这里解决方案有另一个简单的,自己写个计数器,从10记到1,10个线程嘛。这个看个人喜好吧。

    原文:http://babystudyjava.iteye.com/blog/1732814

    展开全文
  • java多线程读取文件

    2015-07-08 23:09:57
    Java多线程读大文件 java多线程文件多线程往队列中写入数据
  • Java多线程读取文件

    2021-08-16 18:48:52
    } } } 多线程读取文件列表 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import redis.clients.jedis.Jedis; import java.io.*; ...

    多线程读取单文件

    package com.qwx.test;
    
    import java.io.*;
    
    /**
     * @ClassName: ReadFile
     * @Description: java类作用描述
     * @Author: qiaowenxuan
     * @CreateDate: 2021/8/16$ 18:36$
     * @Version: 1.0
     */
    public class ReadFile {
        public static void main(String[] args) {
            File file = new File("F://xaa.txt");
            ReaderThread thread1 = new ReaderThread(file);
            ReaderThread thread2 = new ReaderThread(file);
    
            new Thread(thread1,"thread1").start();
            new Thread(thread2,"thread2").start();
        }
    }
    
    class Reader {
        public static void read(File file) throws IOException {
            FileInputStream fileInputStream = new FileInputStream(file);
            InputStreamReader reader = new InputStreamReader(fileInputStream);
            BufferedReader bufferedReader = new BufferedReader(reader);
            String line = null;
            while (null != (line = bufferedReader.readLine())) {
                System.out.println(line);
            }
            bufferedReader.close();
        }
    }
    
    class ReaderThread implements Runnable {
    
        private File file;
        public ReaderThread(File file) {
            this.file = file;
        }
    
        @Override
        public void run() {
            try {
                Reader.read(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    

    多线程读取文件列表

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import redis.clients.jedis.Jedis;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    
    public class FavFileUtil {
        public static List getFileList(String filePath) {
            List fileList = new ArrayList();
            File file = new File(filePath);
            if (!file.isDirectory()) {
                System.out.println("文件【" + file.getName() + "】:" + file.getAbsolutePath());
                fileList.add(file);
            } else {
                System.out.println("文件夹【" + file.getName() + "】:" + file.getAbsolutePath());
                File[] files = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    if (!files[i].isDirectory()) {
                        System.out.println("  文件【" + files[i].getName() + "】:");
                        fileList.add(files[i]);
                    } else if (files[i].isDirectory()) {
                        getFileList(files[i].getAbsolutePath());
                    }
                }
            }
            return fileList;
        }
    
        public static List subFiles(List list, int startIndex, int endIndex) {
            if (endIndex > list.size()) {
                return list.subList(startIndex, list.size());
            }
            return list.subList(startIndex, endIndex);
        }
    
        static int i = 0;
        public static void readFile(File file) throws IOException {
            Jedis jedis = new Jedis("127.0.0.1", 6379);
            //读取文件
            FileInputStream is = new FileInputStream(file);
    
            //获取文件的字符流
            InputStreamReader isr = new InputStreamReader(is);
    
            //缓冲
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            while ((line = br.readLine()) != null) {
                String[] split = line.split("----");
                String key = split[0];
                String val = split[1];
                //if (null == key) key = "";
                //if(null == val) val ="";
                jedis.set(key,val);
                System.out.println(i);
                System.out.println(Thread.currentThread().getName() + ":::" + line);
                System.out.println(Thread.currentThread().getName() + ":::" + key+"----"+val);
                i++;
            }
            br.close();
        }
    
    }
    
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    
    public class FavThreadUtil implements Runnable {
        private List<File> fileList;
        public FavThreadUtil(List fileList) {
            this.fileList = fileList;
        }
        @Override
        public void run() {
            for(File file : fileList){
                try {
                    FavFileUtil.readFile(file);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    
    }
    
    展开全文
  • 多线程读取文件

    2019-05-29 02:40:27
    NULL 博文链接:https://kaobian.iteye.com/blog/1126621
  • 主要介绍了C#实现多线程写入同一个文件的方法,涉及C#多线程操作文件读写的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • 主要为大家详细介绍了java多线程有序读取同一个文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • Qt Creator 多线程读取文件到程序显示 利用QT Creator多任务读取一个文档到程序里 为了防止直接读取文件里的内容太大而发生卡顿,于是多线程读取将更高效的解决这个问题。 效果图如下: 其中pro文件无需改动,...
  • 多线程文件读写操作(java),提高对文件读写效率。
  • C#多线程读取文件

    2021-01-10 17:23:55
    构建多线程实现消费者与生产者的信息读取

    实验报告

    实验目的

    构建线程A1、A2… Ak (k>=3 )和线程B的程序(K生产者和单消费者)。A1、A2… AK从磁盘各自读取一个文本文件,写入到内存中的固定的容器(如Pool)。A1、 A2… Ak读取每一行时,都会休眠,然后在随机的时间(10-100ms)醒来继续尝试执行。程序要求按照A1、A2… Ak的顺序写入Pool。B会观察Pool的状态,如果有新数据,则进行读取,否则B处于等待状态。注意, A1、A2… Ak不能互相干扰。当所有的文件被读取完毕,且B读取完毕时,程序结束。

    实验环境

    VS2019、C#

    功能介绍

    多线程读取文件,将txt文件a1~a6中的内容读取到a7.txt之中

    功能实现过程

    生产者

     private void put(object i)//从磁盘各自读取一个文本文件
            {
                Random random = new Random();
                Monitor.Enter(this);//获取this的排它锁
    
                while (mark || num != (int)i)
                {
                    Monitor.Pulse(this);//丢锁之前都要pulse提醒等待队列里的线程去捡锁,否则等待线程是会一直等待的。
                    Monitor.Wait(this);
                }
    
                //false
                mark = !mark;//当释放时,把锁给get
                string mystr = "";
                FileStream fs = File.OpenRead("a" + Convert.ToString(i) + ".txt");
                StreamReader sr = new StreamReader(fs, Encoding.Default);
                while (sr.Peek() > -1)
                {
                    mystr += sr.ReadLine() + "\n";
                    // Thread.Sleep(random.Next(10, 100));
                }
                pool.Add(mystr);//把文件添加到容器
                mytext2 += mystr;
                sr.Close();
                fs.Close();
                num++;
                Monitor.Pulse(this);
                Monitor.Exit(this);
    
            }
    

    消费者

    private void get()
            {
                for (int i = 0; i < 6; i++)
                {
                    Monitor.Enter(this);
                    while (!mark)
                    {
                        Monitor.Pulse(this);
                        Monitor.Wait(this);
                    }
    
                    mark = !mark;
                    mytext += pool[pool.Count - 1];
                    Monitor.Pulse(this);
                    Monitor.Exit(this);
                }
            }
    

    button控件

     private void button1_Click(object sender, EventArgs e)
            {
                    Thread workth1 = new Thread(put);
                    Thread workth2 = new Thread(put);
                    Thread workth3 = new Thread(put);
                    Thread workth4 = new Thread(put);
                    Thread workth5 = new Thread(put);
                    Thread workth6 = new Thread(put);
                    Thread workth7 = new Thread(get);
                    workth1.Start(1);
                    workth2.Start(2);
                    workth3.Start(3);
                    workth4.Start(4);
                    workth5.Start(5);
                    workth6.Start(6);
    
                    workth7.Start();
                    Thread.Sleep(2000);
                    workth1.Abort();
                    workth2.Abort();
                    workth3.Abort();
                    workth4.Abort();
                    workth5.Abort();
                    workth6.Abort();
                    workth7.Abort();
    
                    richTextBox1.Text = mytext;
                    richTextBox2.Text = mytext2;
            }
    

    实验效果展示

    1.执行之前

    在这里插入图片描述

    2.执行后

    在这里插入图片描述

    展开全文
  • 多线程读取文件

    2019-04-26 01:04:22
    NULL 博文链接:https://wpf-0604.iteye.com/blog/2348093
  • Java多线程读写文件

    千次阅读 2020-04-17 20:56:56
    读写文件是IO密集型任务 过多的线程执行同一个任务,并不一定能提高效率,因为线程切换,需要耗时。再比如IO密集型任务,IO是瓶颈,并不是线程越多,IO会越快。 开多线程去执行任务,需要综合考虑实际情况。 二、...
  • 多线程读写文件实现方法

    万次阅读 2018-08-02 15:03:45
    总结:一般俩中方式 一种是file以共享属性打开,第二种用手动添加读写锁实现 using System; using System.Threading.Tasks; using System.Diagnostics; using System.IO; using System.Threading; using System....
  • Android 多线程读写文件

    千次阅读 2020-10-10 19:39:21
    1.通过多线程多写文件 public class DownloadUtils { public static final String TAG = DownloadUtils.class.getSimpleName(); private File src;// 源文件 private File dst;// 目标文件 private int ...
  • 主要为大家详细介绍了java使用多线程读取超大文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • linux 多线程读写文件

    2021-03-04 17:48:58
    //打开文件,O_CREAT不存在就创建文件,O_EXCL标记防止多线程执行该任务,也就是说有一个线程在执行open人物,其他线程则不能执行这个任务,执行到该open就会退出 if (fd ) //目标文件打开失败 { perror("main: ...
  • 主要为大家详细介绍了Java jdbc批量多线程读取CVS文件入库,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 针对这样的大文件解析处理,解决方案是使用线程,分割读取指定的大文件。获取我们所需要的信息。不说,上代码了,有注释可以帮助理解。 2.代码 package com.thread.multipl.mysolution; import java.io...
  • 主要为大家详细介绍了python多线程分块读取文件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 主要为大家详细介绍了python多线程同步之文件读写控制,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • java多线程读写文件

    千次阅读 2018-04-07 23:11:06
    一、引言 使用java读写文件是日常工作中需要经常使用的技术。为了提高文件写出分析和写出效率,本文采用多线程实现多文件解析和写出。具体实现如下:二、文件读写工具类package ...
  • 但线程中readlines()就已经全部读完文件了...这个问题使用线程的效率价值在requests处,200M的文件读取还轮不到谈文件读取多线程加速。实际上因为GIL,在python的多线程中你也无法提高IO速度。import requestsimpo...
  • c++ 多线程读写txt文件

    2022-02-20 23:54:39
    //本文在c++ builder 10.3平台调试通过 #include // std::cout #include //... //启动1个线程 for (auto& th : threads) th.join(); //等待10个线程结束 thread1.join(); // std::cout ; system("pause"); return 0; }

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 572,557
精华内容 229,022
关键字:

多线程读取文件