Hello I am new in Java so I would like some guidelines on how to organize files of a project in java. Currently I am building an app with GUI so I want two files one that relates to the GUI and another file that relates to any functions that are called from the first. Right now I've named the second file Utilities.java and looks like this:
package Directory;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
public class Utilities {
public class FileCopy{
private File Source;
private File Destination;
private long totalBytes=0L;
FileCopy(File source,File destination){
Source=source;
Destination=destination;
retrieveTotalBytes(source);
}
File getSource(){return Source;}
File getDestination(){return Destination;}
Long gettotalBytes(){return totalBytes;}
private void retrieveTotalBytes(File sourceFile)
{
if(sourceFile.isDirectory()==false){
totalBytes = sourceFile.length();
}
else{
File[] files = sourceFile.listFiles();
for(File file : files)
{
if(file.isDirectory()) retrieveTotalBytes(file);
else totalBytes += file.length();
}
}
System.out.print("Done retrieving");
}
}
public class Copy extends SwingWorker<Void,Integer>
{
File src,dest;
InputStream in;
OutputStream out;
JProgressBar progressBar;
JProgressBar all;
JTextArea txt;
public int progress;
//private int all_progress;
private long totalBytes = 0L;
private long copiedBytes = 0L;
boolean keepStructure=false;
boolean delete=false;
public Copy(File source,File dst,JProgressBar br,JTextArea text,boolean keep,boolean delete)
{
src=source;
dest=dst;
progressBar=br;
txt=text;
progressBar.setValue(0);
progressBar.setVisible(true);
txt.setText("Copying " + src.getName());
keepStructure=keep;
this.delete=delete;
}
#Override
public Void doInBackground() throws Exception
{
txt.setText(src.getName());
//retrieveTotalBytes(src);
copyFiles(src, dest);
return null;
}
#Override
public void process(java.util.List<Integer> chunks)
{
for(int i : chunks)
{
progressBar.setValue(i);
}
}
#Override
public void done()
{
setProgress(100);
}
public String GetParent(String input){
short pos=(short) input.lastIndexOf(File.separatorChar);
return input.substring(0, pos);
}
private void copyFiles(File sourceFile, File targetFile) throws IOException
{
if(sourceFile.isDirectory())
{
if(!targetFile.exists()) targetFile.mkdirs();
String[] filePaths = sourceFile.list();
for(String filePath : filePaths)
{
File destFile;
File srcFile = new File(sourceFile, filePath);
if(keepStructure==true)
destFile= new File(targetFile, filePath);
else{
String filepath2=GetParent(dest.toString())+File.separatorChar+srcFile.getName();
destFile=new File(filepath2);
}
System.out.print("\n\n name="+destFile.toString()+"\n");
System.out.print("dest to string =" +GetParent(dest.toString()) + " srcFile.getName()="+srcFile.getName()+"\n" );
copyFiles(srcFile, destFile);
}
}
else
{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(targetFile));
long fileBytes = sourceFile.length();
long soFar = 0L;
int theByte;
while((theByte = bis.read()) != -1)
{
bos.write(theByte);
setProgress((int) (copiedBytes++ * 100 / totalBytes));
publish((int) (soFar++ * 100 / fileBytes));
}
bis.close();
bos.close();
if(delete==true)
sourceFile.delete();
publish(100);
txt.setText("Copying " + src.getName() + "complete");
}
}
}
}
Question 1:
Notice that in that file the I have two subclasses {FileCopy,Copy} that are completely different. Is that a good way to organize the code or should a move each class on each own file?
Question 2:
Also, in my main i try to create and object from each class but I do something wrong. I've added the import of the file but when I try to create an object e.g.
Copy worker = new Copy(source,dest,progressBar,textArea, keep_Structure,false);
I receive this error:
No enclosing instance of type Utilities is accessible. Must qualify
the allocation with an enclosing instance of type Utilities (e.g.
x.new A() where x is an instance of Utilities).
In Java you should moslty (at least while you are still learning the basics) keep each class in its own file.
You have 3 (and not 2) classes in your file : Utilities, FileCopy and Copy, with the later two being inner classes of Utilities (the Utilities class does nothing on its own). This is why you can't instanciate Copy without first instantiating Utilities.
I think you should have a package named utilities, containing two files : FileCopy.java and Copy.java each containing their own class. If you want a way to differentiate between parts of your application, this is a good way to start : have a package containing all gui-related classes and another one for the rest of the application.
This should solve your error.
The official tutorials on nested classes : http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Related
I try to analyze Java source code in Java6. ANTLR4 does great job in lexical analysis indeed but now I wonder if more advanced problems, such as listing inherited methods, can be managed.
My idea (according to some googling):
load source files
get system compiler by ToolProvider.getSystemJavaCompiler() and compile sources via run() into .class files
[maybe?] pack .class files to .jar and load them somehow
use Java reflection to analyze compiled classes
delete .class files
write output (e.g. inherited methods/fields etc.)
Bullets 1, 4, 5 and 6 are clean enough and well described. I belive nr. 2 can be solved using this tutorial. So my core problem is nr. 3 as I can't figure out how to load .class files and analyse them.
Any ideas? Is this even possible? If so, how? Could you recommend me either a tutorial or examples? Is my idea even correct?
I prefer not using third-party libraries as I'd like to understand in depth.
Thanks to all comments and google I finally figured it out - basically I needed an example like this:
/* Usage
--------
$ javac CompileJarLoadReflect.java
$ java CompileJarLoadReflect MyClass YourClass CompileJarLoadReflect
MyClass.java compilation is successful
YourClass.java compilation is successful
CompileJarLoadReflect.java compilation is successful
3 files successfully compiled
Class MyClass
myMethod
Class YourClass
yourMethod
Class CompileJarLoadReflect
main
compile
compile
load
jar
*/
/* Thanks to
------------
http://www.java2s.com/Code/Java/File-Input-Output/CreateJarfile.htm
http://stackoverflow.com/questions/194698/how-to-load-a-jar-file-at-runtime/673414#673414
*/
import javax.tools.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Method;
/** Simple compilation, packaging and loading example */
public class CompileJarLoadReflect {
/** JAR buffer size*/
public static int BUFFER_SIZE = 10 * 1024;
/** Compile all files given (by their location) */
public void compile(String[] files) throws Exception {
for (String f : files) compile(f + ".java");
System.out.println(files.length + " files successfully compiled");
}
/** Compile one particular file */
protected void compile(String f) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int compilationResult = compiler.run(null, null, null, f);
if (compilationResult == 0) System.out.println(f + " compilation is successful");
else throw new Exception("Compilation error at file " + f);
}
/** Pack tobeJared classes into jarName */
public void jar(String jarName, String[] tobeJared) throws Exception {
File archiveFile = new File(jarName);
byte buffer[] = new byte[BUFFER_SIZE];
FileOutputStream stream = new FileOutputStream(archiveFile);
JarOutputStream out = new JarOutputStream(stream, new Manifest());
for (String name : tobeJared) {
File f = new File(name + ".class");
if (f == null || !f.exists() || f.isDirectory()) throw new Exception("Jar problem at file " + name);
JarEntry jarAdd = new JarEntry(f.getName());
jarAdd.setTime(f.lastModified());
out.putNextEntry(jarAdd);
FileInputStream in = new FileInputStream(f);
while (true) {
int nRead = in.read(buffer, 0, buffer.length);
if (nRead <= 0) break;
out.write(buffer, 0, nRead);
}
in.close();
}
out.close();
stream.close();
}
/** Load jar archive at jarName and then print methods of all classes in clazzes */
public void load(String jarName, String[] clazzes) throws Exception {
File file = new File(jarName);
URL url = file.toURL();
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
for (String c : clazzes) {
System.out.println("Class " + c);
Class cls = cl.loadClass(c);
Method[] methods = cls.getDeclaredMethods();
for (Method m : methods) System.out.println("\t" + m.getName());
}
}
/** Try everyting out, use params without .java */
public static void main(String[] args) {
String jarName = "output.jar";
try {
CompileJarLoadReflect cjlr = new CompileJarLoadReflect();
cjlr.compile(args);
cjlr.jar(jarName, args);
cjlr.load(jarName, args);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I hope it helps others.
My project is to create an Android app that can perform feature extraction and classification of audio files. So first, I'm creating a Java application as a test run.
I'm attempting to use jAudio's feature extractor package to extract audio features from an audio file.
As a starter, I want to input a .wav file and run the feature extraction operation upon that file, and then store the results as an .ARFF file.
However, I'm getting the below NullPointer Exception error from a package within the project:
Exception in thread "main" java.lang.NullPointerException
at java.io.DataOutputStream.writeBytes(Unknown Source)
at jAudioFeatureExtractor.jAudioTools.FeatureProcessor.writeValuesARFFHeader(FeatureProcessor.java:853)
at jAudioFeatureExtractor.jAudioTools.FeatureProcessor.<init>(FeatureProcessor.java:258)
at jAudioFeatureExtractor.DataModel.extract(DataModel.java:308)
at Mfccarffwriter.main(Mfccarffwriter.java:70)
Initially I thought it was a file permission issue(i.e, the program was not being allowed to write a file because of lack of permissions), but even after granting every kind of permission to Eclipse 4.2.2(I'm running Windows 7, 64 bit version), I'm still getting the NullException bug.
The package code where the offending exception originates from is given below:
/**
* Write headers for an ARFF file. If saving for overall features, this must
* be postponed until the overall features have been calculated. If this a
* perWindow arff file, then all the feature headers can be extracted now
* and no hacks are needed.
* <p>
* <b>NOTE</b>: This procedure breaks if a feature to be saved has a
* variable number of dimensions
*
* #throws Exception
*/
private void writeValuesARFFHeader() throws Exception {
String sep = System.getProperty("line.separator");
String feature_value_header = "#relation jAudio" + sep;
values_writer.writeBytes(feature_value_header); // exception here
if (save_features_for_each_window && !save_overall_recording_features) {
for (int i = 0; i < feature_extractors.length; ++i) {
if (features_to_save[i]) {
String name = feature_extractors[i].getFeatureDefinition().name;
int dimension = feature_extractors[i]
.getFeatureDefinition().dimensions;
for (int j = 0; j < dimension; ++j) {
values_writer.writeBytes("#ATTRIBUTE \"" + name + j
+ "\" NUMERIC" + sep);
}
}
}
values_writer.writeBytes(sep);
values_writer.writeBytes("#DATA" + sep);
}
}
Here's the main application code:
import java.io.*;
import java.util.Arrays;
import com.sun.xml.internal.bind.v2.runtime.RuntimeUtil.ToStringAdapter;
import jAudioFeatureExtractor.Cancel;
import jAudioFeatureExtractor.DataModel;
import jAudioFeatureExtractor.Updater;
import jAudioFeatureExtractor.Aggregators.AggregatorContainer;
import jAudioFeatureExtractor.AudioFeatures.FeatureExtractor;
import jAudioFeatureExtractor.AudioFeatures.MFCC;
import jAudioFeatureExtractor.DataTypes.RecordingInfo;
import jAudioFeatureExtractor.jAudioTools.*;
public static void main(String[] args) throws Exception {
// Display information about the wav file
File extractedFiletoTest = new File("./microwave1.wav");
String randomID = Integer.toString((int) Math.random());
String file_path = "E:/Weka-3-6/tmp/microwave1.wav";
AudioSamples sampledExampleFile = new AudioSamples(extractedFiletoTest,randomID,false);
RecordingInfo[] samplefileInfo = new RecordingInfo[5];
samplefileInfo[1] = new RecordingInfo(randomID, file_path, sampledExampleFile, true);
double samplingrate= sampledExampleFile.getSamplingRateAsDouble();
int windowsize= 4096;
boolean normalize = false;
OutputStream valsavepath = new FileOutputStream(".\\values");
OutputStream defsavepath = new FileOutputStream(".\\definitions");
boolean[] featurestosaveamongall = new boolean[10];
Arrays.fill(featurestosaveamongall, Boolean.TRUE);
double windowoverlap = 0.0;
DataModel mfccDM = new DataModel("features.xml",null);
mfccDM.extract(windowsize, 0.5, samplingrate, true, true, false, samplefileInfo, 1); /// invokes the writeValuesARFFHeader function.
}
}
You can download the whole project (done so far)here.
This may be a bit late but I had the same issue and I tracked it down to the featureKey and featureValue never being set in the DataModel. There is not a set method for these but they are public field. Here is my code:
package Sound;
import jAudioFeatureExtractor.ACE.DataTypes.Batch;
import jAudioFeatureExtractor.DataModel;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class Analysis {
private static String musicFile = "/home/chris/IdeaProjects/AnotherProj/res/SheMovesInHerOwnWay15s.wav";
private static String featureFile = "/home/chris/IdeaProjects/AnotherProj/res/features.xml";
private static String settingsFile = "/home/chris/IdeaProjects/AnotherProj/res/settings.xml";
private static String FKOuputFile = "/home/chris/IdeaProjects/AnotherProj/res/fk.xml";
private static String FVOuputFile = "/home/chris/IdeaProjects/AnotherProj/res/fv.xml";
public static void main(String[] args){
Batch batch = new Batch(featureFile, null);
try{
batch.setRecordings(new File[]{new File(musicFile)});
batch.getAggregator();
batch.setSettings(settingsFile);
DataModel dm = batch.getDataModel();
OutputStream valsavepath = new FileOutputStream(FVOuputFile);
OutputStream defsavepath = new FileOutputStream(FKOuputFile);
dm.featureKey = defsavepath;
dm.featureValue = valsavepath;
batch.setDataModel(dm);
batch.execute();
}
catch (Exception e){
e.printStackTrace();
}
}
}
I created the settings.xml file using the GUI and just copied the features.xml file from the directory where you saved the jar.
Hope this helps
Servlet is very good looking and reading files that have English names like hello.txt. It does not want to read files that have a Russian name, such pushkin.txt. Is anyone able to help to solve this problem?
Here is the code:
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class servlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public static List<String> getFileNames(File directory, String extension) {
List<String> list = new ArrayList<String>();
File[] total = directory.listFiles();
for (File file : total) {
if (file.getName().endsWith(extension)) {
list.add(file.getName());
}
if (file.isDirectory()) {
List<String> tempList = getFileNames(file, extension);
list.addAll(tempList);
}
}
return list;
}
#SuppressWarnings("resource")
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException{
response.setContentType("text/html; charset=UTF-8");
String myName = request.getParameter("text");
List<String> files = getFileNames(new File("C:\\Users\\vany\\Desktop\\test"), "txt");
for (String string : files) {
if (myName.equals(string)) {
try {
File file = new File("C:\\Users\\vany\\Desktop\\test\\" + string);
FileReader reader = new FileReader(file);
int b;
PrintWriter writer = response.getWriter();
writer.print("<html>");
writer.print("<head>");
writer.print("<title>HelloWorld</title>");
writer.print("<body>");
writer.write("<div>");
while((b = reader.read()) != -1) {
writer.write((char) b);
}
writer.write("</div>");
writer.print("</body>");
writer.print("</html>");
}
finally {
if(reader != null) {
try{
reader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
}
The question is relevant, the problem is not solved
I thought that you have a problem whith the statements
for (String string : files) {
if (myName.equals(string)) {
I would compare in this way
for (File file: files) {
if (myName.equals(file.getName())) {
I hope that it help you.
Note: Thanks for the comments, you can try it.
Greetings
First of all I would use a debugger to check what's wrong with that code. It's quite difficult to find a bug without running the code. If you don't want to use a debugger print out all filenames found in the directory to ensure that some file names were found:
for (String string : files) {
System.out.println(string)
....
If files were found I would check whether I have rights to write to them. It might be that the application has not proper permissions to write in selected directory.
Are files "hello.txt" and pushkin.txt directly inside "C:\Users\vany\Desktop\test\" folder? Or is pushkin.txt file in another folder from "C:\Users\vany\Desktop\test\"?
Can you show us how you invoke the servlet?
If you have pushkin.txt in another folder and you invoke the servlet with something like "folder\pushkin.txt" it will not work because getFileNames() returns file names (without folder) and "myName.equals(string)" fails as "folder\pushkin.txt" is not equal to "pushkin.txt"
For the past couple of months I've been working on a game in java for a university project. It's coming up to the end of the project and I would like to compile the project into a single file which is easy to distribute. The game currently runs from inside the IDE and relies on the working directory being set somewhere specific (i.e. the content directory with sounds/textures etc). What's the best way to put all this together for portability? I'm hoping there is some way to compile the content into the jar file...
NB. I'm using NetBeans, so any solutions which are easy in netbeans get extra credit ;)
Addendum::
For future reference, I found a way of accessing things by directory, ythis may not be the best way but it works:
File directory = new File(ClassLoader.getSystemResource("fullprototypeone/Content/Levels/").toURI());
And now I can just use that file object as normal
You can embed resources in jar file - this is just a zip after all. The standard way to do that is to put resource files in some directory in your sources hierachy. Then you refer to them by Object.getClass().getResourceAsStream(). So you will need to change the way you retrieve them in your code.
You can read more here: Object.getClass().getResourceAsStream(). Of course instead of object you use some class from your package.
when you put those resource files in your src hierachy I believe Netbeans should jar them for you with standard build of the project.
Here is the manual for JNLP and Java Web Start. These technologies exist just for the task you've described.
Well one way is to access the resources via Class.getResourceAsStream (or Class.getResource). Then make sure that the files are in the JAR file.
Off the top of my head (and without trying it) you should be able to put the resources in with the source files which will get NetBeans to put them into the JAR file. Then change the File stuff to the getResource calls.
I would suggest making a simple program that plays a sound and trying it out before you try to convert the whole project over.
If you try and it doesn't work let me know and I'll see if I can dig into it a bit more (posting the code of the simple project would be good if it comes to that).
Here is the code I promised in another comment... it isn't quite what I remember but it might get you started.
Essentially you call: String fileName = FileUtils.getFileName(Main.class, "foo.txt");
and it goes and finds that file on disk or in a JAR file. If it is in the JAR file it extracts it to a temp directory. You can then use "new File(fileName)" to open the file which, no matter where it was before, will be on the disk.
What I would do is take a look at the getFile method and look at what you can do with the JAR file to iterate over the contents of it and find the files in a given directory.
Like I said, not exactly what you want, but does do a lot of the initial work for you.
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
public class FileUtils
{
public static String getFileName(final Class<?> owner,
final String name)
throws URISyntaxException,
ZipException,
IOException
{
String fileName;
final URI uri;
try
{
final String external;
final String decoded;
final int pos;
uri = getResourceAsURI(owner.getPackage().getName().replaceAll("\\.", "/") + "/" + name, owner);
external = uri.toURL().toExternalForm();
decoded = external; // URLDecoder.decode(external, "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
catch(final FileNotFoundException ex)
{
fileName = null;
}
if(fileName == null || !(new File(fileName).exists()))
{
fileName = getFileNameX(owner, name);
}
return (fileName);
}
private static String getFileNameX(final Class<?> clazz, final String name)
throws UnsupportedEncodingException
{
final URL url;
final String fileName;
url = clazz.getResource(name);
if(url == null)
{
fileName = name;
}
else
{
final String decoded;
final int pos;
decoded = URLDecoder.decode(url.toExternalForm(), "UTF-8");
pos = decoded.indexOf(":/");
fileName = decoded.substring(pos + 1);
}
return (fileName);
}
private static URI getResourceAsURI(final String resourceName,
final Class<?> clazz)
throws URISyntaxException,
ZipException,
IOException
{
final URI uri;
final URI resourceURI;
uri = getJarURI(clazz);
resourceURI = getFile(uri, resourceName);
return (resourceURI);
}
private static URI getJarURI(final Class<?> clazz)
throws URISyntaxException
{
final ProtectionDomain domain;
final CodeSource source;
final URL url;
final URI uri;
domain = clazz.getProtectionDomain();
source = domain.getCodeSource();
url = source.getLocation();
uri = url.toURI();
return (uri);
}
private static URI getFile(final URI where,
final String fileName)
throws ZipException,
IOException
{
final File location;
final URI fileURI;
location = new File(where);
// not in a JAR, just return the path on disk
if(location.isDirectory())
{
fileURI = URI.create(where.toString() + fileName);
}
else
{
final ZipFile zipFile;
zipFile = new ZipFile(location);
try
{
fileURI = extract(zipFile, fileName);
}
finally
{
zipFile.close();
}
}
return (fileURI);
}
private static URI extract(final ZipFile zipFile,
final String fileName)
throws IOException
{
final File tempFile;
final ZipEntry entry;
final InputStream zipStream;
OutputStream fileStream;
tempFile = File.createTempFile(fileName.replace("/", ""), Long.toString(System.currentTimeMillis()));
tempFile.deleteOnExit();
entry = zipFile.getEntry(fileName);
if(entry == null)
{
throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
}
zipStream = zipFile.getInputStream(entry);
fileStream = null;
try
{
final byte[] buf;
int i;
fileStream = new FileOutputStream(tempFile);
buf = new byte[1024];
i = 0;
while((i = zipStream.read(buf)) != -1)
{
fileStream.write(buf, 0, i);
}
}
finally
{
close(zipStream);
close(fileStream);
}
return (tempFile.toURI());
}
private static void close(final Closeable stream)
{
if(stream != null)
{
try
{
stream.close();
}
catch(final IOException ex)
{
ex.printStackTrace();
}
}
}
}
Edit:
Sorry, I don't have time to work on this right now (if I get some I'll do it and post the code here). This is what I would do though:
Look at the ZipFile class and use the entries() method to find all of the files/directories in the zip file.
the ZipEntry has an isDirectory() method that you can use to figure out what it is.
I think the code I posted in this answer will give you a way to pick a temporary directory to extract the contents to.
I think the code I posted in this answer could help with copying the ZipEntry contents to the file system.
once the items are on the file system the code you already have for iterating over the directory would still work. You would add a new method to the FileUtils class in the code above and be able to find all of the files as you are doing now.
There is probably a better way to do it, but off the top of my head I think that will work.
yes ! put your compiled .class files and your resources with folders in a jar file .. you ll have to build a manifest file as well .. you can find the tutorial about making a .jar file on
google. most probably you ll be referred to java.sun.com .
I use this test to convert txt to pdf :
package convert.pdf;
//getResourceAsStream(String name) : Returns an input stream for reading the specified resource.
//toByteArray : Get the contents of an InputStream as a byte[].
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import convert.pdf.txt.TextConversion;
public class TestConversion {
private static byte[] readFilesInBytes(String file) throws IOException {
return IOUtils.toByteArray(TestConversion.class.getResourceAsStream(file));
}
private static void writeFilesInBytes(byte[] file, String name) throws IOException {
IOUtils.write(file, new FileOutputStream(name));
}
//just change the extensions and test conversions
public static void main(String args[]) throws IOException {
ConversionToPDF algorithm = new TextConversion();
byte[] file = readFilesInBytes("/convert/pdf/text.txt");
byte[] pdf = algorithm.convertDocument(file);
writeFilesInBytes(pdf, "text.pdf");
}
}
Problem:
Exception in thread "main" java.lang.NullPointerException
at org.apache.commons.io.IOUtils.copyLarge(IOUtils.java:1025)
at org.apache.commons.io.IOUtils.copy(IOUtils.java:999)
at org.apache.commons.io.IOUtils.toByteArray(IOUtils.java:218)
at convert.pdf.TestConversion.readFilesInBytes(TestConversion.java:17)
at convert.pdf.TestConversion.main(TestConversion.java:28)
I use the debugger, and the problem seems to be located here :
private static byte[] readFilesInBytes(String file) throws IOException {
return IOUtils.toByteArray(TestConversion.class.getResourceAsStream(file));
}
What is my problem?
Sounds like the resource probably doesn't exist with that name.
Are you aware that Class.getResourceAsStream() finds a resource relative to that class's package, whereas ClassLoader.getResourceAsStream() doesn't? You can use a leading forward slash in Class.getResourceAsStream() to mimic this, so
Foo.class.getResourceAsStream("/bar.png")
is roughly equivalent to
Foo.class.getClassLoader().getResourceAsStream("bar.png")
Is this actually a file (i.e. a specific file on the normal file system) that you're trying to load? If so, using FileInputStream would be a better bet. Use Class.getResourceAsStream() if it's a resource bundled in a jar file or in the classpath in some other way; use FileInputStream if it's an arbitrary file which could be anywhere in the file system.
EDIT: Another thing to be careful of, which has caused me problems before now - if this has worked on your dev box which happens to be Windows, and is now failing on a production server which happens to be Unix, check the case of the filename. The fact that different file systems handle case-sensitivity differently can be a pain...
Are you checking to see if the file exists before you pass it to readFilesInBytes()? Note that Class.getResourceAsStream() returns null if the file cannot be found. You probably want to do:
private static byte[] readFilesInBytes(String file) throws IOException {
File testFile = new File(file);
if (!testFile.exists()) {
throw new FileNotFoundException("File " + file + " does not exist");
}
return IOUtils.toByteArray(TestConversion.class.getResourceAsStream(file));
}
or better yet:
private static byte[] readFilesInBytes(String file) throws IOException {
InputStream stream = TestConversion.class.getResourceAsStream(file);
if (stream == null) {
throw new FileNotFoundException("readFilesInBytes: File " + file
+ " does not exist");
}
return IOUtils.toByteArray(stream);
}
This class reads a TXT file in the classpath and uses TextConversion to convert to PDF, then save the pdf in the file system.
Here TextConversion code :
package convert.pdf.txt;
//Conversion to PDF from text using iText.
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import convert.pdf.ConversionToPDF;
import convert.pdf.ConvertDocumentException;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Font;
import com.lowagie.text.Paragraph;
import com.lowagie.text.pdf.PdfWriter;
public class TextConversion implements ConversionToPDF {
public byte[] convertDocument(byte[] documents) throws ConvertDocumentException {
try {
return this.convertInternal(documents);
} catch (DocumentException e) {
throw new ConvertDocumentException(e);
} catch (IOException e) {
throw new ConvertDocumentException(e);
}
}
private byte[] convertInternal(byte[] documents) throws DocumentException, IOException {
Document document = new Document();
ByteArrayOutputStream pdfResultBytes = new ByteArrayOutputStream();
PdfWriter.getInstance(document, pdfResultBytes);
document.open();
BufferedReader reader = new BufferedReader( new InputStreamReader( new ByteArrayInputStream(documents) ) );
String line = "";
while ((line = reader.readLine()) != null) {
if ("".equals(line.trim())) {
line = "\n"; //white line
}
Font fonteDefault = new Font(Font.COURIER, 10);
Paragraph paragraph = new Paragraph(line, fonteDefault);
document.add(paragraph);
}
reader.close();
document.close();
return pdfResultBytes.toByteArray();
}
}
And here the code to ConversionToPDF :
package convert.pdf;
// Interface implemented by the conversion algorithms.
public interface ConversionToPDF {
public byte[] convertDocument(byte[] documentToConvert) throws ConvertDocumentException;
}
I think the problem come from my file system (devbox on windows and server is Unix).
I will try to modify my classpath.
This problem may be caused by calling methods on test.txt, which can be a folder shortcut. In other words, you're calling a method on a file that doesn't exist, resulting in a NullPointerException.