I'm on Java 6 and I have a method that scans the runtime classpath for a file called config.xml. If found, I would like to read the contents of the file into a string:
InputStream istream = this.getClass().getClassLoader().getResourceAsStream("config.xml");
if(istream != null) {
System.out.println("Found config.xml!");
StringBuffer fileData = new StringBuffer(1000);
BufferedReader reader;
try {
reader = new BufferedReader(new FileReader(fileName));
char[] buf = new char[1024];
int numRead = 0;
while((numRead=reader.read(buf)) != -1) {
String readData = String.valueOf(buf, 0, numRead);
fileData.append(readData);
buf = new char[1024];
reader.close();
}
} catch (FileNotFoundException fnfExc) {
throw new RuntimeException("FileNotFoundException: " + fnfExc.getMessage());
} catch (IOException ioExc) {
throw new RuntimeException("IOException: " + ioExc.getMessage());
}
}
When I run this code, I get the following console output:
Found config.xml!
Exception in thread "main" java.lang.RuntimeException: FileNotFoundException: config.xml (No such file or directory)
at com.me.myapp.Configurator.readConfigFileFromClasspath(Configurator.java:556)
at com.me.myapp.Configurator.<init>(Configurator.java:34)
...rest of stack trace omitted for brevity
So the classpath scan for config.xml is successful, but then the reader can't seem to find the file. Why??? My only theory is that when config.xml is found on the classpath, it doesn't contain an absolute path to the location of the file on the file system, and perhaps that's what the reader code is looking for.
You use a resource from a classloader.
Instead of doing:
InputStream istream = this.getClass().getClassLoader().getResourceAsStream("config.xml");
do:
URL url = getClass().getResource("config.xml");
That URL will have the path (use .toURI().getPath()). To open the matching input stream afterwards, use .openStream().
You know at least that the resource exists: if it doesn't, .getResource{,AsStream}() both return null (instead of throwing an IOException, which is doubtful imho)
From your given example, it is not clear what fileName refers to. You should just use the stream you got from getResourceAsStream()to read you file, something along
reader = new BufferedReader(new InputStreamReader(istream));
And you should avoid to repeatedly allocating buf new for every read cycle, once is enough.
Related
is it possible to write/create an exe file in Java?
I can successfully read it but writing the exact same data that has been read to a new file seems to create some trouble because Windows tell's me it's not supported for my pc anymore.
This is the code I'm using to read the file where path is a String given with the actual path (it's in the .jar itself that's why I'm using ResourceAsStream()):
try {
InputStream inputStream = FileIO.class.getResourceAsStream(path);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
ArrayList<String> _final = new ArrayList<String>();
String line;
while ((line = reader.readLine()) != null) {
_final.add(line);
}
inputStream.close();
return _final.toArray(new String[_final.size()]);
}catch(Exception e) {
return null;
}
This is the code I'm using to write the file:
public static void writeFileArray(String path, String[] data) {
String filename = path;
try{
FileWriter fileWriter = new FileWriter(filename);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
for(String d : data) {
bufferedWriter.write(d + "\n");
}
bufferedWriter.close();
}
catch(IOException ex){
System.out.println("FileIO failed to write file, IO exception");
}
}
So it doesn't give me any error's or something and the file size of the original .exe and the 'transferred' .exe stays the same, but it doesn't work anymore. Am I just doing it wrong? Did I forget something? Can u even do this with Java?
Btw I'm not that experienced with reading/writing files..
Thanks for considering my request.
I'm going to guess that you're using a Reader when you should be using a raw input stream. Use BufferedInputStream instead of BufferedReader.
BufferedInputStream in = new BufferedInputStream( inputStream );
The problem is that Reader interprets the binary as your local character set instead of the data you want.
Edit: if you need a bigger hint start with this. I just noticed you're using a BufferedWriter too, that won't work either.
try {
InputStream inputStream = FileIO.class.getResourceAsStream(path);
BufferedInputStream in = new BufferedInputStream( inputStream );
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] bytes = new byte[ 1024 ];
for( int length; ( length = ins.read( bytes ) ) != -1; )
bos.write( bytes, 0, length );
}
inputStream.close();
return bos;
When you are using Java 7 or newer, you should copy a resource to a file using
public static void copyResourceToFile(String resourcePath, String filePath) {
try(InputStream inputStream = FileIO.class.getResourceAsStream(resourcePath)) {
Files.copy(inputStream, Paths.get(filePath));
}
catch(IOException ex){
System.out.println("Copying failed. "+ex.getMessage());
}
}
This construct ensures correct closing of the resources even in the exceptional case and the JRE method ensures correct and efficient copying of the data.
It accepts additional options, e.g. to specify that the target file should be overwritten in case it already exists, you would use
public static void copyResourceToFile(String resourcePath, String filePath) {
try(InputStream inputStream = FileIO.class.getResourceAsStream(resourcePath)) {
Files.copy(inputStream, Paths.get(filePath), StandardCopyOption.REPLACE_EXISTING);
}
catch(IOException ex){
System.out.println("Copying failed. "+ex.getMessage());
}
}
You are using InputStreams for strings, .exe files are bytes!
Try using a ByteArrayInputStream and ByteArrayOutputStream.
Edit: completing with markspace's answer:
new BufferedInputStream(new ByteArrayInputStream( ... ) )
I have a simple java program that reads a line from file and writes it to another file.
My source file has words like: it's but the destination file is having words like it�s.
I am using BufferedReader br = new BufferedReader(new FileReader(inputFile)); to read the source file and PrintWriter writer = new PrintWriter(resultFile, "UTF-8"); to write the destination file.
How to get the actual character in my destination file too?
You need to specify a CharacterSet when creating the BufferedReader, otherwise the platform default encoding is used:
BufferedReader br = new BufferedReader(new FileReader(inputFile),"UTF-8");
I know this question is a bit old, but I thought I'd put down my answer anyway.
You can use java.nio.file.Files to read the file and java.io.RandomAccessFile to write to your destination file. For example:
public void copyContentsOfFile(File source, File destination){
Path p = Paths.get(source.toURI());
try {
byte[] bytes = Files.readAllBytes(p);
RandomAccessFile raf = new RandomAccessFile(destination, "rw");
raf.writeBytes(new String(bytes));
raf.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I want to retrieve file from ftp server, I have also used Apache poi client.retrieveFile() method, but I'm unable to open it which is showing:
excel cannot open file check file extension and file format. check file is not corrupted
Then I used file reader and writer. Below is my code snippet.
public void testFileWriter()
{
try{
FTPFile[] files = client.listFiles("/Ftp1");
for (FTPFile file : files) {
File serverFile = new File("D:/Pondi.xlsx");
if(!serverFile.isFile())
{
serverFile.createNewFile();
}
BufferedWriter writer = new BufferedWriter(new FileWriter(serverFile));
client.enterLocalPassiveMode();
InputStream inputStream = client.retrieveFileStream("/Ftp1/"+ file.getName());
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
System.out.println("Created Reader");
while(reader.read()!=-1)
{
String temp = reader.readLine();
System.out.println(temp);
writer.write(temp);
}
writer.flush();
writer.close();
reader.close();
}
}
catch(IOException ioe){
ioe.printStackTrace();
}
}
Please help me to resolve this crucial issue.
You have to use an API for working with it. You can't read these files like reading normal text files.
JExcel will be good for your need.
Examples are be available here
For copying files make use of this. Reading the file for copying by the method that you used won't work properly.
Hope will be helpful for you.
If you want to read and copy binary data, you must not use reader.readLine(), because there are no lines in a binary file. Therefore, this attempt will most likely fail.
Copy it like this instead:
int fileNo = 0;
for (FTPFile file : files) {
File serverFile = new File("D:/Pondi_" + fileNo + ".xlsx");
...
InputStream in = client.retrieveFileStream("/Ftp1/"+ file.getName());
OutputStream out = new FileOutputStream(serverFile);
// read and copy binary data
byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) > 0){
out.write(buf, 0, len);
}
in.close();
out.close();
fileNo++;
}
Beside that, consider giving your files a different name that D:/Pondi.xlsx, because otherwise the file gets overridden again and again in the loop. I did this with fileNo.
I've got a Servlet on which a user can upload a .jar file to check its MANIFEST.MF.
I know the following would work:
JarInputStream in = new JarInputStream(new ByteArrayInputStream (fileItem.get()));
Manifest mf = in.getManifest();
Unfortunately the getManifest() method parses for Key: Value and needs the ": " (colon+space), a simple colon is not enough. Since the mobile phones I'm working with also work if the MANIFEST.MF only has colons and not colon+space, I'd like to extract the MANIFEST.MF manually, but I don't want to save the file on disk.
If I'd have a JarFile, I could parse the Manifest via:
JarFile jarFile = new JarFile(fileName);
InputStream in = jarFile.getInputStream(jarFile.getEntry("META-INF/MANIFEST.MF"));
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = br.readLine()) != null) {
String[] splitAr = line.split(":", 0);
// ...
But unfortunately I have no idea how I could convert a JarInputStream (or a ByteArrayInputStream) to a JarFile.
What I would try to do in this case:
iterate through all the entries in the jar using getNextEntry() -- not getNextJarEntry()! and see if you can reach the manifest this way
try to use a ZipInputStream instead which is more generic -- JarInputStream in fact extends it -- and that should give you access to get the META-INF/MANIFEST.MF file.
This is not supported by the standard API. The only way to construct a JarFile is by providing a File reference, and since the API does not provide an interface to create "special files" backed by for instance an InputStream, it is not possible to solve it.
If you're on a UNIX system, you could probably set up a device file some how, but you would lose portability.
private static void copyFiles(JarInputStream in, JarOutputStream out)
throws IOException
{
JarEntry inEntry;
byte[] buffer = new byte[4096];
while ((inEntry=(JarEntry)in.getNextEntry())!=null)
{if (inEntry.getMethod()==0)
{out.putNextEntry(new JarEntry(inEntry));
}
else
{out.putNextEntry(new JarEntry(inEntry.getName()));
}
//InputStream data=in;//the call to ZipInputStream.getNextEntry() positions the InputStream at the start of the entry and therefore supplying the ZipInputStream is the equivalent of supplying a ZipEntry's InputStream.the ZipInputStream is smart enough to handle the entry's EOF downstream
int num;
while ((len=/*data*/in.read(buffer))>0)
{out.write(buffer, 0, len);
}
out.flush();
}
}
You can read manifest from input stream as string an parse it by yourself
/**
* Read JAR manifest as String from input stream.
* Like JarInputStream, assume that META-INF/MANIFEST.MF entry should be either
* the first or the second entry (when preceded by the dir META-INF/).
*/
def readManifestAsString(InputStream is) {
def zip = new ZipInputStream(is);
def e = zip.getNextEntry();
if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
e = zip.getNextEntry();
if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
byte[] bytes = getBytes(new BufferedInputStream(zip));
return new String(bytes, "UTF8");
}
}
byte[] getBytes(InputStream is) {
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
int n;
while ((n = is.read(buffer, 0, buffer.length)) != -1) {
baos.write(buffer, 0, n);
}
return baos.toByteArray();
}
JAR Manifest specification can be found here
Is there a way to prepend a line to the File in Java, without creating a temporary file, and writing the needed content to it?
No, there is no way to do that SAFELY in Java. (Or AFAIK, any other programming language.)
No filesystem implementation in any mainstream operating system supports this kind of thing, and you won't find this feature supported in any mainstream programming languages.
Real world file systems are implemented on devices that store data as fixed sized "blocks". It is not possible to implement a file system model where you can insert bytes into the middle of a file without significantly slowing down file I/O, wasting disk space or both.
The solutions that involve an in-place rewrite of the file are inherently unsafe. If your application is killed or the power dies in the middle of the prepend / rewrite process, you are likely to lose data. I would NOT recommend using that approach in practice.
Use a temporary file and renaming. It is safer.
There is a way, it involves rewriting the whole file though (but no temporary file). As others mentioned, no file system supports prepending content to a file. Here is some sample code that uses a RandomAccessFile to write and read content while keeping some content buffered in memory:
public static void main(final String args[]) throws Exception {
File f = File.createTempFile(Main.class.getName(), "tmp");
f.deleteOnExit();
System.out.println(f.getPath());
// put some dummy content into our file
BufferedWriter w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(f)));
for (int i = 0; i < 1000; i++) {
w.write(UUID.randomUUID().toString());
w.write('\n');
}
w.flush();
w.close();
// append "some uuids" to our file
int bufLength = 4096;
byte[] appendBuf = "some uuids\n".getBytes();
byte[] writeBuf = appendBuf;
byte[] readBuf = new byte[bufLength];
int writeBytes = writeBuf.length;
RandomAccessFile rw = new RandomAccessFile(f, "rw");
int read = 0;
int write = 0;
while (true) {
// seek to read position and read content into read buffer
rw.seek(read);
int bytesRead = rw.read(readBuf, 0, readBuf.length);
// seek to write position and write content from write buffer
rw.seek(write);
rw.write(writeBuf, 0, writeBytes);
// no bytes read - end of file reached
if (bytesRead < 0) {
// end of
break;
}
// update seek positions for write and read
read += bytesRead;
write += writeBytes;
writeBytes = bytesRead;
// reuse buffer, create new one to replace (short) append buf
byte[] nextWrite = writeBuf == appendBuf ? new byte[bufLength] : writeBuf;
writeBuf = readBuf;
readBuf = nextWrite;
};
rw.close();
// now show the content of our file
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(f)));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
}
You could store the file content in a String and prepend the desired line by using a StringBuilder-Object. You just have to put the desired line first and then append the file-content-String.
No extra temporary file needed.
No. There are no "intra-file shift" operations, only read and write of discrete sizes.
It would be possible to do so by reading a chunk of the file of equal length to what you want to prepend, writing the new content in place of it, reading the later chunk and replacing it with what you read before, and so on, rippling down the to the end of the file.
However, don't do that, because if anything stops (out-of-memory, power outage, rogue thread calling System.exit) in the middle of that process, data will be lost. Use the temporary file instead.
private static void addPreAppnedText(File fileName) {
FileOutputStream fileOutputStream =null;
BufferedReader br = null;
FileReader fr = null;
String newFileName = fileName.getAbsolutePath() + "#";
try {
fileOutputStream = new FileOutputStream(newFileName);
fileOutputStream.write("preappendTextDataHere".getBytes());
fr = new FileReader(fileName);
br = new BufferedReader(fr);
String sCurrentLine;
while ((sCurrentLine = br.readLine()) != null) {
fileOutputStream.write(("\n"+sCurrentLine).getBytes());
}
fileOutputStream.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
fileOutputStream.close();
if (br != null)
br.close();
if (fr != null)
fr.close();
new File(newFileName).renameTo(new File(newFileName.replace("#", "")));
} catch (IOException ex) {
ex.printStackTrace();
}
}
}