Why can't I read from /proc in Java using Commons IO FileUtils, but can do so using a plain FileInputStream?
Asked Answered
F

4

2

I had a problem with reading /proc/%d/stat files using my Java method copyFiles() (source code below). I have found workaround using similar readProc() method.

Now I am wondering what was the problem. Output files were created, but each file had 0 bytes (in /proc/ all files are 0 bytes because it is not standard filesystem). FileUtils is from the Apache Commons IO library.

I've tried to do the same using java.nio - again, IOException is being thrown that attributes are wrong for each file.

I removed some part of the code regarding parsing exceptions etc.

Why does this work with FileInputStream, but not with FileUtils.copyFile()?

public void copyFiles() {
    final File dir = new File("/proc");
    final String[] filedirArray = dir.list();
    long counter = 0;
    for(String filedir : filedirArray) {
            final File checkFile = new File(dir, filedir);
            if (checkFile.isDirectory()) {
                    try {
                            Integer.parseInt(filedir);
                            File srcFile = new File(checkFile, "stat");
                            File dstFile = new File("/home/waldekm/files/stat" + "." + Long.toString(counter++));
                            try {                                    
                                FileUtils.copyFile(srcFile, dstFile);
                            } catch (IOException e1) {}
                    } catch (NumberFormatException e) {
                            // not a number, do nothing
                    }                        
            }
    }
}

public static void readProc(final String src, final String dst) {
    FileInputStream in = null;
    FileOutputStream out = null;

    File srcFile = new File(src);
    File dstFile = new File(dst);

    try {
        in = new FileInputStream(srcFile);
        out = new FileOutputStream(dstFile);
        int c;
        while((c = in.read()) != -1) {
            out.write(c);
        }
    } catch (IOException e1) {
 }  finally {

        try {
            if (in != null) {
                in.close();
            }
        } catch (IOException e1) {}
        try {
            if (out != null) {
                out.close();
            }
        } catch (IOException e1) {}
    }
Funnelform answered 16/8, 2011 at 12:8 Comment(2)
Why is this tagged android? Your code won't work on Android, as it refers to directories that do not exist.Fyn
Actually, it is from the android project. Directory name is just an example.Funnelform
B
2

The reason is most likely that the operating system is reporting the file size as zero.

On my machine, man 2 stat says this:

"For most files under the /proc directory, stat() does not return the file size in the st_size field; instead the field is returned with the value 0."

(The stat system call will be what the JVM uses to find out what a file's size is.)

Burchfield answered 16/8, 2011 at 12:43 Comment(6)
you if i just open any proc file in java and try to read using .read() method then it will not work? right...in may case .read gives -1 and in kernel space proc read doesnt execuatateEvonneevonymus
@Mr.32 - No. That's not what we are talking about. We are talking about what stat reports as the file size. If a process has the relevant privilege then it should have no problem reading from /proc. (Try running the program as root ...)Burchfield
i have given 666 to that /proc file so that should not be problemEvonneevonymus
Read this: https://mcmap.net/q/2036582/-linux-file-permission ... about why you can't access /proc/... files even though the "mode" says you should be able to.Burchfield
Nope. FileInputStream.read() doesn't use stat() to determine end of stream. It uses a C read() returning zero.Cranmer
@Cranmer that’s the point. That’s why copying using just FileInputStream.read() works (because it doesn’t care whether stat() reports a zero size). Whereas the most likely reason FileUtils.copyFile() does not work (or did not work back then when the question was asked) is/was that it does check the file size upfront, to optimize the operation.Ambience
E
1

Here is a code snipped that would read specific fields from a proc file, using methods that are available (but not documented directly) in the Process class of Android. Modify the FORMAT buffer and the output buffer size to read more/different values from the proc file,

int PROC_SPACE_TERM = (int)' ';
int PROC_OUT_LONG = 0x2000

public static final int[] PROCESS_STATS_FORMAT = new int[] {
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM,
    PROC_SPACE_TERM|PROC_OUT_LONG,                  // 13: utime
    PROC_SPACE_TERM|PROC_OUT_LONG                   // 14: stime
};

long buf[] = new long[2];

try {
    int pid = 1000; // Assume 1000 is a valid pid for a process. 
    Method mReadProcFile = 
              Process.class.getMethod("readProcFile", String.class,
                                      int[].class, String[].class,   
                                      long[].class, float[].class);
    mReadProcFile.invoke(null, "/proc/" + pid + "/stat", 
                         PROCESS_STATS_FORMAT, null, buf, null);

    return buf;

} catch(NoSuchMethodException e) {
    Log.e(TAG, "Error! Could not get access to JNI method - readProcFile");
} catch (InvocationTargetException e) {
Log.e(TAG, "Error! Could not invoke JNI method - readProcFile");
} catch (IllegalAccessException e) {
    Log.e(TAG, "Error! Illegal access while invoking JNI method - readProcFile");
}

return null;
Expostulatory answered 23/6, 2013 at 14:35 Comment(0)
B
0

copyFile checks the lengths of the source and dest files afterwards and will throw an exception if not matching. As the source file is under /proc (File.length returns 0) and the destination file is not (File.length will return the content length), they will differ in length and an IOException thrown. Source:

 if (srcFile.length() != destFile.length()) {
            throw new IOException("Failed to copy full 

Related: Reading a file under /proc using for example FileUtils.readFileToString or any calls reading into a String or Writer has another problem but for the same reason.

It's using InputStreamReader which in turn is calling available() on the InputStream.

The call to available() hangs indefinately if called on an inputstream opened on a File under the /proc tree.

Solution in all cases is to use read(byte[]) until -1 is returned instead.

Bim answered 20/6 at 13:29 Comment(0)
C
-1

I see you are creating a FileInputStream to read a /proc file. Instead I suggest you create a FileReader object. FileInputStream gets tripped up by the lack of file length for /proc files but FileReader does not.

Clamor answered 15/1, 2017 at 3:18 Comment(1)
'Gets tripped up' how? FileReader uses FileInputStream under the hood, so what you describe is impossible, and your proposed solution changes nothing.Cranmer

© 2022 - 2024 — McMap. All rights reserved.