Writing to stdin
Overview
System.in or stdin is usually used as an InputStream. However on Linux you can access this stream in other ways.Accessing file descriptor 0
In linux, each file descriptor is accessible via /proc/{process-id}/fd/{file-id} You can use this to see what files a process has open but also see the contents of a file.Writing and memory mapping
Getting the process id in Java is obscure, but once you have this you can re-open existing file descriptors such as stdin, file descriptor 0.int processId = Integer.parseInt(ManagementFactory.getRuntimeMXBean().getName().split("@")[0]); RandomAccessFile raf = new RandomAccessFile("/proc/" + processId + "/fd/0", "rw"); final FileChannel fc = raf.getChannel(); final MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()); bb.putLong(System.nanoTime()); bb.force(); raf.close();
This opens the System.in is a read-write mode and memory maps it before changing its contents.
When you run this program it looks like
$ echo " " > file.dat $ od -xc file.dat 0000000 2020 2020 2020 2020 000a \n 0000011 $ java -cp . Main < file.dat $ od -xc file.dat 0000000 0000 5522 11a9 79c6 000a \0 \0 " U 251 021 306 y \n 0000011At first is rather surprising you can write to stdin or even memory map it. What happens if stdin is not a real file.
$ echo " " | java -cp . Main Exception in thread "main" java.io.FileNotFoundException: /proc/7935/fd/0 (Text file busy) at java.io.RandomAccessFile.open(Native Method) at java.io.RandomAccessFile.(RandomAccessFile.java:233) at java.io.RandomAccessFile. (RandomAccessFile.java:118) at Main.main(Main.java:10)
I think even pipes are considered files. Though they are read or write only.
ReplyDeleteYou can use FileInputStream, but you can't memory map them. The apparent size is 0 bytes for a pipe.
ReplyDelete