线程已经通过之前的创建文件指令,将文件创建并打开,但是在进行写数据提示errno9 Bad File Descriptor

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线程已经通过之前的创建文件指令,将文件创建并打开,但是在进行写数据提示errno9 Bad File Descriptor相关的知识,希望对你有一定的参考价值。

多线程切换,造成文件描述符不能用的问题
(sd.fd=open(sd.path,O_TRUNC|O_CREAT|O_RDWR,0777))<0),跪求请大神指教!

参考技术A 用的指令是
gcc -D_REENTRANT -I/usr/include/nptl book_h32.c -o book_h32 -L/usr/lib/nptl -lpthread thread thread.c (后面两个是产生文件名和源文件名)程序是抄的书上的,本身没有问题。
错误 LNK1120 为您提供该链接的无法解析的外部对象数 (number)。导致无法解析的外部对象的条件由错误 LNK2001 描述,此错误出现在该错误信息之前(对每个无法解析的外部对象都出现一次)。
//就是说每出现一次LNK1120都会在之前出现一个LNK2001
LNK2001
所以主要是解决LNK1120关键是要解决链接器工具错误 LNK2001 这分一下的情况(来自VS 2008的帮助),在这里我只复制一些比较常见的,如果还不行,你重建工程来吧~~

一、代码问题
1.如果 LNK2001 诊断文本报告 __check_commonlanguageruntime_version 是无法解析的外部符号,在 function 中找到了未定义的外部符号 (symbol)。若要解决此错误,请提供符号定义或移除引用它的代码。
2.成员模板的定义超出了类的范围。Visual C++ 的一个限制是,成员模板的定义必须完全位于封闭类内。
3.代码中大小写不匹配
4.如果项目使用函数内联,但在 .cpp 文件而非头文件中定义函数,则会导致 LNK2001。
5.试图引用没有外部链接的函数或数据会导致 LNK2001。
6.缺少函数主体或变量会导致 LNK2001。
7.调用参数类型与函数声明中的参数类型不匹配的函数会导致 LNK2001。名称修饰将函数参数合并到最终修饰函数名中。

8.错误包含的原型导致编译器需要没有提供的函数体,这样会导致 LNK2001。如果同时具有函数 F 的类实现和非类实现,请注意 C++ 范围解析规则。

9.在使用 C++ 时,将函数原型包含在类定义中但未能包含实现(该类的此函数的实现)会导致 LNK2001。

10.试图从抽象基类的构造函数或析构函数调用纯虚函数会导致 LNK2001。纯虚函数没有基类实现。

11.试图在函数范围外使用用该函数声明的变量(局部变量)会导致 LNK2001。

二、编译和链接问题
1.项目缺少对库 (.LIB) 或对象 (.OBJ) 文件的引用。有关更多信息,请参见用作链接器输入的 .lib 文件。

2.如果使用 /NODEFAULTLIB 或 /Zl,包含所需代码的库将不会链接到项目,除非已显式地包括了这些库。(在使用 /clr 或 /clr:pure 进行编译时,您将看到对 .cctor 的引用;有关更多信息,请参见 混合程序集的初始化。)

3.如果正在使用 Unicode 和 MFC,如果没有创建 wWinMainCRTStartup 的入口点,将在 _WinMain@16 上得到无法解析的外部对象;请使用 /ENTRY。请参见 Unicode 编程摘要。

4.将用 /MT 编译的代码与库 LIBC.lib 链接会在 _beginthread、_beginthreadex、_endthread 和 _endthreadex 上导致 LNK2001。

5.链接需要多线程库的代码(任何 MFC 代码或用 /MT 编译的代码)会在 _beginthread、_beginthreadex、_endthread 和 _endthreadex 上导致 LNK2001。有关更多信息,请参见下列知识库文章:

6.在用 /MD 进行编译时,因为所有的运行时现在都存放在一个 DLL 中,所以源中的“func”引用在对象中变为“__imp__func”引用。如果试图与 LIBC.lib 或 LIBCMT.lib 静态库链接,则将在 __imp__func 上得到 LNK2001。当不用 /MD 进行编译时,如果试图与 MSVCxx.lib 链接,则并非总是得到 LNK2001,但可能会有其他问题。

7.在生成应用程序的调试版本时与发布模式库链接会导致 LNK2001。同样,使用 /Mxd 选项(/MTd 或 /MDd)和/或定义 _DEBUG,然后再与版本库链接,将可能会产生无法解析的外部对象(同时还会出现其他问题)。将发布模式生成与调试库链接同样会导致类似问题。

8.将 Microsoft 库版本和编译器产品版本混合可能会有问题。新编译器版本的库可能包含早期版本的库中没有的新符号。可能需要更改搜索路径中的目录顺序,或将它们更改为指向当前版本。

9.使用库文件选择下的“工具”|“选项”|“项目”|“VC++ 目录”对话框,可以更改搜索顺序。项目的“属性页”对话框中的“链接器”文件夹可能也包含可能已过期的路径。

10.当安装了新的 SDK(可能在不同的位置),但没有将搜索顺序更新为指向新位置时,可能会出现此问题。通常情况下,应将新 SDK 的 include 目录和 lib 目录的路径放在默认 Visual C++ 位置的前面。另外,包含嵌入路径的项目可能仍然指向旧路径,这些路径是有效的,但对于安装到不同位置的新版本所添加的新功能已过期。

11.编译器供应商之间、甚至同一编译器的不同版本之间当前没有 C++ 命名标准。因此,链接用其他编译器编译的对象文件可能无法生成相同的命名方案,从而导致错误 LNK2001。

12.在不同模块上混合内联和非内联编译选项会导致 LNK2001。如果创建 C++ 库时打开了函数内联(/Ob1 或 /Ob2),但描述函数的相应头文件的内联是关闭的(没有 inline 关键字),则将发生此错误。若要防止此问题,请在要包含到其他文件中的头文件中用 inline 定义内联函数。

13.如果使用 #pragma inline_depth 编译器指令,请确保具有 设置为 2 或更大的值,并确保使用 /Ob1 或 /Ob2 编译器选项。

14.在创建纯资源 DLL 时省略 LINK 选项 /NOENTRY 将导致 LNK2001。

15.使用不正确的 /SUBSYSTEM 或 /ENTRY 设置会导致 LNK2001。例如,如果编写基于字符的应用程序(控制台应用程序)并指定 /SUBSYSTEM:WINDOWS,您将得到无法解析的 WinMain 外部对象。有关这些选项和入口点的更多信息,请参见 /SUBSYSTEM 和 /ENTRY 链接器选项。
初学者在学习VC++的过程中,遇到的LNK2001错误的错误消息主要为:
unresolved external symbol “symbol”(不确定的外部“符号”)。
如果连接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误消息。一般来说,发生错误的原因有两个:一是所引用的函数、变量不存在、拼写不正确或者使用错误;其次可能使用了不同版本的连接库。
以下是可能产生LNK2001错误的原因:
一.由于编码错误导致的LNK2001。
1.不相匹配的程序代码或模块定义(.DEF)文件能导致LNK2001。例如, 如果在C++ 源文件内声明了一变量“var1”,却试图在另一文件内以变量“VAR1”访问该变量,将发生该错误。
2.如果使用的内联函数是在.CPP文件内定义的,而不是在头文件内定义将导致LNK2001错误。
3.调用函数时如果所用的参数类型同函数声明时的类型不符将会产生LNK2001。
4.试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001。
5.要注意函数和变量的可公用性,只有全局变量、函数是可公用的。 静态函数和静态变量具有相同的使用范围限制。当试图从文件外部访问任何没有在该文件内声明的静态变量时将导致编译错误或LNK2001。
函数内声明的变量(局部变量) 只能在该函数的范围内使用。
C++ 的全局常量只有静态连接性能。这不同于C,如果试图在C++的多个文件内使用全局变量也会产生LNK2001错误。一种解决的方法是需要时在头文件中加入该常量的初始化代码,并在.CPP文件中包含该头文件;另一种方法是使用时给该变量赋以常数。
二.由于编译和链接的设置而造成的LNK2001
1.如果编译时使用的是/NOD(/NODEFAULTLIB)选项,程序所需要的运行库和MFC库在连接时由编译器写入目标文件模块, 但除非在文件中明确包含这些库名,否则这些库不会被链接进工程文件。在这种情况下使用/NOD将导致错误LNK2001。
2.如果没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时将得到“unresolved external on _WinMain@16”的LNK2001错误信息。
3.使用/MD选项编译时,既然所有的运行库都被保留在动态链接库之内,源文件中对“func”的引用,在目标文件里即对“__imp__func” 的引用。如果试图使用静态库LIBC.LIB或LIBCMT.LIB进行连接,将在__imp__func上发生LNK2001;如果不使用/MD选项编译,在使用MSVCxx.LIB连接时也会发生LNK2001。
4.使用/ML选项编译时,如用LIBCMT.LIB链接会在_errno上发生LNK2001。
5.当编译调试版的应用程序时,如果采用发行版模态库进行连接也会产生LNK2001;同样,使用调试版模态库连接发行版应用程序时也会产生相同的问题。
6.不同版本的库和编译器的混合使用也能产生问题,因为新版的库里可能包含早先的版本没有的符号和说明。
7.在不同的模块使用内联和非内联的编译选项能够导致LNK2001。如果创建C++库时打开了函数内联(/Ob1或/Ob2),但是在描述该函数的相应头文件里却关闭了函数内联(没有inline关键字),这时将得到该错误信息。为避免该问题的发生,应该在相应的头文件中用inline关键字标志内联函数。
8.不正确的/SUBSYSTEM或/ENTRY设置也能导致LNK2001。
其实,产生LNK2001的原因还有很多,以上的原因只是一部分而已,对初学者来说这些就够理解一阵子了。但是,分析错误原因的目的是为了避免错误的发生。LNK2001错误虽然比较困难,但是只要注意到了上述问题,还是能够避免和予以解决的。

29多线程(线程池定时器)将一个文件复制多次拆分文件并合并多线程复制文件

线程池

程序启动一个新线程成本是比较高的,因为它涉及到与操作系统交互。而使用线程池可以很好的提高性能,尤其是

当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

在JDK 5之前,我们必须手动实现自己的线程池,从JDK 5开始,Java内置支持线程池。

package org.westos.demo;

import java.util.concurrent.*;

/**
 * @author lwj
 * @date 2020/6/7 8:36
 */
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        线程池:容器,存有一定数量线程对象的容器
        JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
		public static ExecutorService newCachedThreadPool():			根据任务的数量来创建线程对应的线程个数
		public static ExecutorService newFixedThreadPool(int nThreads):	固定初始化几个线程
		public static ExecutorService newSingleThreadExecutor():			初始化一个线程的线程池
        这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
            Future<?> submit(Runnable task)
            <T> Future<T> submit(Callable<T> task)
        使用步骤:
            创建线程池对象
            创建Runnable实例
            提交Runnable实例
            关闭线程池
         */
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程执行了这个任务");
            }
        });
        //根据任务数量创建相应数量的线程对象
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("提交第二个任务");
            }
        });
        Future<Integer> submit = executorService.submit(new MyCallable());
        System.out.println(submit.get());

        executorService.shutdown();
        //关闭线程池
    }
}

class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        return 100;
    }
}
package org.westos.demo2;

import java.util.concurrent.*;

/**
 * @author lwj
 * @date 2020/6/7 8:36
 */
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        线程池:容器,存有一定数量线程对象的容器
        JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
		public static ExecutorService newCachedThreadPool():			根据任务的数量来创建线程对应的线程个数
		public static ExecutorService newFixedThreadPool(int nThreads):	固定初始化几个线程
		public static ExecutorService newSingleThreadExecutor():			初始化一个线程的线程池
        这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
            Future<?> submit(Runnable task)
            <T> Future<T> submit(Callable<T> task)
        使用步骤:
            创建线程池对象
            创建Runnable实例
            提交Runnable实例
            关闭线程池
         */
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });

        executorService.shutdown();
    }
}
package org.westos.demo3;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author lwj
 * @date 2020/6/7 8:36
 */
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        线程池:容器,存有一定数量线程对象的容器
        JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
		public static ExecutorService newCachedThreadPool():			根据任务的数量来创建线程对应的线程个数
		public static ExecutorService newFixedThreadPool(int nThreads):	固定初始化几个线程
		public static ExecutorService newSingleThreadExecutor():			初始化一个线程的线程池
        这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
            Future<?> submit(Runnable task)
            <T> Future<T> submit(Callable<T> task)
        使用步骤:
            创建线程池对象
            创建Runnable实例
            提交Runnable实例
            关闭线程池
         */
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });

        executorService.shutdown();
    }
}

定时器与定时任务

package org.westos.demo4;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 定时器
 * @author lwj
 * @date 2020/6/7 9:28
 */
public class MyTest {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //TimerTask抽象类
        MyTimerTask myTimerTask = new MyTimerTask(timer);
        timer.schedule(myTimerTask, 3000);
        //等3s后执行该定时任务

        // 取消定时器
        // timer.cancel();
    }
}

class MyTimerTask extends TimerTask {
    public Timer timer;

    public MyTimerTask(Timer timer) {
        this.timer = timer;
    }

    @Override
    public void run() {
        System.out.println("时间到了");
        timer.cancel();
    }
}
package org.westos.demo4;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @author lwj
 * @date 2020/6/7 9:36
 */
public class MyTest2 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        MyTimerTask2 myTimerTask2 = new MyTimerTask2();
        timer.schedule(myTimerTask2, 3000, 1000);
        //等3s后执行此任务,以后间隔1s重复执行定时任务
    }
}

class MyTimerTask2 extends TimerTask {

    @Override
    public void run() {
        System.out.println("时间到了");
    }
}
package org.westos.demo4;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author lwj
 * @date 2020/6/7 9:38
 */
public class MyTest3 {
    public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();
        MyTimerTask3 myTimerTask3 = new MyTimerTask3();
        //myTimerTask2.cancel(); 取消定时任务

        String str = "2020-06-07 09:49:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date parse = sdf.parse(str);

        timer.schedule(myTimerTask3, parse);
        //指定某个时间执行定时任务
    }
}

class MyTimerTask3 extends TimerTask {

    @Override
    public void run() {
        System.out.println("时间到了");
    }
}

指定时间删除文件夹

package org.westos.demo4;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 定时删除一个文件夹
 * @author lwj
 * @date 2020/6/7 9:49
 */
public class MyDemo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //定时器

        File source = new File("E:\\新建文件夹");
        TimerTaskDemo timerTaskDemo = new TimerTaskDemo(source, timer);

        timer.schedule(timerTaskDemo, 5000);
        //延迟5s后执行定时任务,删除文件夹
    }
}

class TimerTaskDemo extends TimerTask {
    public File directory;
    public Timer timer;

    public TimerTaskDemo(File directory, Timer timer) {
        this.directory = directory;
        this.timer = timer;
    }

    @Override
    public void run() {
        //删除文件夹并关闭定时器
        deleteDir(directory);
        timer.cancel();
        //取消定时器
    }

    public void deleteDir(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                deleteDir(file1);
            }
        }
        file.delete();
        //删除文件或者空文件夹
    }
}

练习题

1、把一个文件复制多次

package org.westos.demo5;

import java.io.*;

/**
 * @author lwj
 * @date 2020/6/7 15:11
 */
public class MyTest {
    public static void main(String[] args) throws IOException {
        File source = new File("C:\\Users\\shawn\\Music\\MV\\G.E.M. 邓紫棋-我说了算(多芬秀发合作单曲)(蓝光).mp4");
        RandomAccessFile rw = new RandomAccessFile(source, "rw");
        byte[] bytes = new byte[1024 * 8];
        int len = 0;
        for (int i = 0; i < 3; i++) {
            FileOutputStream fos = new FileOutputStream(new File("E:\\music", "G.E.M" + i + ".mp4"));
            while ((len = rw.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
                fos.flush();
            }
            fos.close();
            //每复制一个文件,将随机读取流的指针重置为0
            rw.seek(0);
        }
        rw.close();
    }
}

2、拆分文件并合并

package org.westos.demo5;

import java.io.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;

/**
 * @author lwj
 * @date 2020/6/7 15:24
 */
public class MyTest2 {
    public static void main(String[] args) throws IOException {
        split();
        merge();
    }

    private static void merge() throws IOException {
        File source = new File(".");
        System.out.println(source.getAbsolutePath());
        File[] files = source.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isFile() && pathname.length() <= 1024 * 1024 && pathname.getName().endsWith(".mp3");
            }
        });
        Vector<FileInputStream> vector = new Vector<>();
        for (File file : files) {
            vector.addElement(new FileInputStream(file));
        }
        Enumeration<FileInputStream> elements = vector.elements();
        SequenceInputStream sis = new SequenceInputStream(elements);

        byte[] bytes = new byte[1024];
        int len = 0;
        FileOutputStream fos = new FileOutputStream(new File("百事.mp3"));
        while ((len = sis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
            fos.flush();
        }
        fos.close();
        sis.close();
    }

    private static void split() throws IOException {
        //把一份文件拆分为多份,每份1M,然后合并
        File source = new File("C:\\Users\\shawn\\Music\\G.E.M. 邓紫棋 _ 王嘉尔 - 热爱就一起.mp3");

        FileInputStream fis = new FileInputStream(source);
        byte[] bytes = new byte[1024 * 1024];
        int len = 0;
        int index = 0;
        while ((len = fis.read(bytes)) != -1) {
            FileOutputStream fos = new FileOutputStream(new File(index++ + ".mp3"));
            fos.write(bytes, 0, len);
            fos.close();
        }
        fis.close();
    }
}

3、多线程复制文件

package org.westos.demo5;

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

/**
 * @author lwj
 * @date 2020/6/7 15:49
 */
public class MyDemo {
    public static void main(String[] args) throws FileNotFoundException {
        //多线程复制同一份文件
        File source = new File("C:\\Users\\shawn\\Music\\G.E.M. 邓紫棋 _ 王嘉尔 - 热爱就一起.mp3");
        File destFile = new File(".\\邓紫棋-热爱就一起.mp3");
        long length = source.length();
        //文件的总大小
        long threadNums = 3;
        long average = length / threadNums;
        for (int i = 0; i < 3; i++) {
            long start = i * (average + 1);
            long end = (i + 1) * average;
            new CopyFileThread(start, end, source, destFile).start();
        }
        //如果3个线程不能均分,那么再添加一个线程
        if (length % threadNums != 0) {
            long start = threadNums * average + 1;
            new CopyFileThread(start, length, source, destFile).start();
        }
    }
}


class CopyFileThread extends Thread {
    public long start;
    public long end;
    public RandomAccessFile in;
    public RandomAccessFile out;

    public CopyFileThread(long start, long end, File srcFile, File destFile) throws FileNotFoundException {
        this.start = start;
        this.end = end;
        this.in = new RandomAccessFile(srcFile, "rw");
        this.out = new RandomAccessFile(destFile, "rw");
    }

    @Override
    public void run() {
        try {
            in.seek(start);
            out.seek(start);
            //设置读写起始指针
            byte[] bytes = new byte[1024 * 8];
            int len = 0;
            long pointer = in.getFilePointer();
            while (pointer <= end && (len = in.read(bytes)) != -1) {
                //最后一次有可能只剩余1KB,然而最后一次还是会读取8KB,然后pointer > end退出while
                out.write(bytes, 0, len);
                pointer += len;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

以上是关于线程已经通过之前的创建文件指令,将文件创建并打开,但是在进行写数据提示errno9 Bad File Descriptor的主要内容,如果未能解决你的问题,请参考以下文章

多线程文件压缩

在完成 zip 创建之前将 zip 内容发送到响应

С.创建线程

phpadmin创建自动更新

Linux常用指令

linux下使用eclipse打开esp32工程文件,并进行编译下载。