I have been trying out object ox io for Java. It has been working well on Android hence I decided to go with it on Java desktop implementation.
The problem I am facing is that I can save my data at run time but when I restart the app or desktop app the data is gone, is forgotten, which is very strange. I have tried to look for an explanation but haven't found anything on this. Can anyone help or have an idea why this is? In the mean time I have reverted to using SQLite. The app is intended to be very big and have a lot of multi-threads.
here is a sample
import io.objectbox.BoxStore;
import io.objectbox.DebugFlags;
import lombok.SneakyThrows;
import java.io.File;
import java.io.IOException;
public class DBObjectManager {
public static DBObjectManager objectIOAccessInstance ;
private BoxStore store;
private DBObjectManager() {
File tempFile = null;
try {
tempFile = File.createTempFile("objectdb", "");
} catch (IOException e) {
e.printStackTrace();
}
tempFile.delete();
store = MyObjectBox.builder()
.directory(tempFile)
.debugFlags(DebugFlags.LOG_QUERIES | DebugFlags.LOG_QUERY_PARAMETERS)
.build();
}
public static DBObjectManager getinstance() {
if (objectIOAccessInstance == null) {
objectIOAccessInstance = new DBObjectManager();
}
return objectIOAccessInstance;
}
public BoxStore getStore() {
return store;
}
}
You are creating a new temporary file each time when you execute your application. I guess that explains your problem.
From the docs:
creates a new empty file in the specified directory. deleteOnExit()
method is called to delete the file created by this method.
I'm new to Java, and I am facing this issue in Eclipse. Even after pointing it to the correct file, it shows a file not Found Error.
I am trying to compile code from a Java file using the Java Compiler API.
The code words fine in Visual Studio with setting everything in root, But gives this error in Eclipse with all these directories.
Also, why are there three different src folders in the image?
My project structure
package com.example.app;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.IOException;
public class compilier {
public static void main(String[] args) throws IOException {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, new File("com/example/app/Code.java").getAbsolutePath());
if (result == 0)
{
System.out.println("File Compiled");
}
try {
String package_dir = "/demo/src/main/java/com/example/app";
try{
ProcessBuilder builder = new ProcessBuilder("java", package_dir.concat("/Code"));
builder.redirectErrorStream(true);
File outfile = new File((package_dir.concat("/output.txt")));
builder.redirectOutput();
builder.start();
if (outfile.length() > 3000)
{
System.out.println("Exceeded buffer limit");
System.exit(1);
}
} catch(IOException e) {
e.printStackTrace();
}
} catch (Exception err) {
System.out.println("Error!");
err.printStackTrace();
}
}
}
Error Message
Your path looks wrong. The /demo directory would need to be in the root of your current drive.
Also, the output of a Maven build is found in the target directory. The Java class files are generated there, and the resource files are copied over from src/main/res hierarchy. The .Java files are lost. You could add a Maven task to copy the .Java files but this would be very nonstandard.
Finally you need to load resource files using the classpath. There are lots of examples on the Internet. Otherwise you may end up with a project that finds the file in Eclipse but not when deployed in a .jar or .war file.
Happy hunting.
I'm trying to use tesseract to do OCR on an image in java. I realize there are wrappers like Tess4J that provide a bunch more functionality and stuff, but I've been struggling to get it set up properly. Simply running a one-line command with Runtime is really all I need anyways since this is just a personal little project and doesn't need to work on other computers or anything.
I have this code:
import java.io.IOException;
public class Test {
public static void main(String[] args) {
System.out.println(scan("full-path-to-test-image"));
}
public static String scan(String imgPath) {
String contents = "";
String cmd = "[full-path-to-tesseract-binary] " + imgPath + " stdout";
try { contents = execCmd(cmd); }
catch (IOException e) { e.printStackTrace(); }
return contents;
}
public static String execCmd(String cmd) throws java.io.IOException {
java.util.Scanner s = new java.util.Scanner(Runtime.getRuntime().exec(cmd).getInputStream()).useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}
}
When it's compiled and run directly from terminal, it works perfectly. When I open the exact same file in eclipse, however, it gives an IOException:
java.io.IOException: Cannot run program "tesseract": error=2, No such file or directory
What's going on? Thank you for any help.
Check the working folder in the run configuration for the Test class in Eclipse. I bet it's different from the one when you run the same program from a terminal.
I've been browsing the site since yesterday and I can't see to find anything that answers my question, so I decided to just ask.
I'm making a pretty basic java GUI, it's designed to be run alongside files that wont be included in the actual java package for compatibility and easier customization of those files, I doubt they could be included either way as they have their own .jars and other things.
So, the problem I'm having is that the GUI application is in the main folder and I need it to locate and open txt files a couple sub-folders deep, in notepad without requiring a full file path as I'll be giving this project out to some people when it's done.
Currently I've been using this to open the files, but will only work for files in the main folder and trying to edit in any file paths did not work.
private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {
Runtime rt=Runtime.getRuntime();
String file;
file = "READTHIS.txt";
try {
Process p=rt.exec("notepad " +file);
} catch (IOException ex) {
Logger.getLogger(NumberAdditionUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
if someone knows a way to do this, that'd be great.
On another note, I'd like to include the file shown above (READTHIS.txt) inside the actual java package, where would I put the file and how should I direct java towards it?
I've been away from java for a long time so I've forgotten pretty much anything, so simpler explanations are greatly appreciated.
Thanks to anyone reading this and any help would be awesome.
Update 2
So I added to the ConfigBox.java source code and made jButton1 open home\doc\READTHIS.txt in Notepad. I created an executable jar and the execution of the jar, via java -jar Racercraft.jar, is shown in the image below. Just take the example of what I did in ConfigBox.java and apply it to NumberAdditionUI.java for each of its JButtons, making sure to change the filePath variable to the corresponding file name that you would like to open.
Note: The contents of the JTextArea in the image below were changed during testing, my code below does not change the contents of the JTextArea.
Directory structure:
\home
Rasercraft.jar
\docs
READTHIS.txt
Code:
// imports and other code left out
public class ConfigBox extends javax.swing.JFrame {
// curDir will hold the absolute path to 'home\'
String curDir; // add this line
/**
* Creates new form ConfigBox
*/
public ConfigBox()
{
// this is where curDir gets set to the absolute path of 'home/'
curDir = new File("").getAbsolutePath(); // add this line
initComponents();
}
/*
* irrelevant code
*/
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed
Runtime rt = Runtime.getRuntime();
// filePath is set to 'home\docs\READTHIS.txt'
String filePath = curDir + "\\docs\\READTHIS.txt"; // add this line
try {
Process p = rt.exec("notepad " + filePath); // add filePath
} catch (IOException ex) {
Logger.getLogger(NumberAdditionUI.class.getName()).log(Level.SEVERE, null, ex);
}
// TODO add your handling code here:
}//GEN-LAST:event_jButton1ActionPerformed
/*
* irrelevant code
*/
Update
This is the quick and dirty approach, if you would like me to add a more elegant solution just let me know. Notice that the file names and their relative paths are hard-coded as an array of strings.
Image of the folder hierarchy:
Code:
Note - This will only work on Windows.
import java.io.File;
import java.io.IOException;
public class Driver {
public static void main(String[] args) {
final String[] FILE_NAMES = {"\\files\\READTHIS.txt",
"\\files\\sub-files\\Help.txt",
"\\files\\sub-files\\Config.txt"
};
Runtime rt = Runtime.getRuntime();
// get the absolute path of the directory
File cwd = new File(new File("").getAbsolutePath());
// iterate over the hard-coded file names opening each in notepad
for(String file : FILE_NAMES) {
try {
Process p = rt.exec("notepad " + cwd.getAbsolutePath() + file);
} catch (IOException ex) {
// Logger.getLogger(NumberAdditionUI.class.getName())
// .log(Level.SEVERE, null, ex);
}
}
}
}
Alternative Approach
You could use the javax.swing.JFileChooser class to open a dialog that allows the user to select the location of the file they would like to open in Notepad.
I just coded this quick example using the relevant pieces from your code:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class Driver extends JFrame implements ActionListener {
JFileChooser fileChooser; // the file chooser
JButton openButton; // button used to open the file chooser
File file; // used to get the absolute path of the file
public Driver() {
this.fileChooser = new JFileChooser();
this.openButton = new JButton("Open");
this.openButton.addActionListener(this);
// add openButton to the JFrame
this.add(openButton);
// pack and display the JFrame
this.pack();
this.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
// handle open button action.
if (e.getSource() == openButton) {
int returnVal = fileChooser.showOpenDialog(Driver.this);
if (returnVal == JFileChooser.APPROVE_OPTION) {
// from your code
Runtime rt = Runtime.getRuntime();
try {
File file = fileChooser.getSelectedFile();
String fileAbsPath = file.getAbsolutePath();
Process p = rt.exec("notepad " + fileAbsPath);
} catch (IOException ex) {
// Logger.getLogger(NumberAdditionUI.class.getName())
// .log(Level.SEVERE, null, ex);
}
} else {
System.exit(1);
}
}
}
public static void main(String args[]) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Driver driver = new Driver();
}
});
}
}
I've also included a link to some helpful information about the FileChooser API, provided by Oracle: How to use File Choosers. If you need any help figuring out the code just let me know, via a comment, and I'll try my best to help.
As for including READTHIS.txt inside the actual java package, take a gander at these other StackOverflow questions:
Getting file from same package?
Reading a text file from a specific package?
How to include text files with executable jar?
Creating runnable jar with external files included?
Including a text file inside a jar file and reading it?
I want to prevent the user from running my java application multiple times in parallel.
To prevent this, I have created a lock file when am opening the application, and delete the lock file when closing the application.
When the application is running, you can not open an another instance of jar. However, if you kill the application through task manager, the window closing event in the application is not triggered and the lock file is not deleted.
How can I make sure the lock file method works or what other mechanism could I use?
You could use a FileLock, this also works in environments where multiple users share ports:
String userHome = System.getProperty("user.home");
File file = new File(userHome, "my.lock");
try {
FileChannel fc = FileChannel.open(file.toPath(),
StandardOpenOption.CREATE,
StandardOpenOption.WRITE);
FileLock lock = fc.tryLock();
if (lock == null) {
System.out.println("another instance is running");
}
} catch (IOException e) {
throw new Error(e);
}
Also survives Garbage Collection.
The lock is released once your process ends, doesn't matter if regular exit or crash or whatever.
Similar discussion is at
http://www.daniweb.com/software-development/java/threads/83331
Bind a ServerSocket. If it fails to bind then abort the startup. Since a ServerSocket can be bound only once, only single instsances of the program will be able to run.
And before you ask, no. Just because you bind a ServerSocket, does not mean you are open to network traffic. That only comes into effect once the program starts "listening" to the port with accept().
I see two options you can try:
Use a Java shutdown hook
Have your lock file hold the main process number. The process should exist when you lanuch another instance. If it's not found in your system, you can assume that the lock can be dismissed and overwritten.
Creating a server socket, bounds to a specific port with a ServerSocket instance as the application starts is a straight way.
Note that ServerSocket.accept() blocks, so running it in its own thread makes sense to not block the main Thread.
Here is an example with a exception thrown as detected :
public static void main(String[] args) {
assertNoOtherInstanceRunning();
... // application code then
}
public static void assertNoOtherInstanceRunning() {
new Thread(() -> {
try {
new ServerSocket(9000).accept();
} catch (IOException e) {
throw new RuntimeException("the application is probably already started", e);
}
}).start();
}
You could write the process id of the process that created the lock file into the file.
When you encounter an existing lock file, you do not just quit, but you check if the process with that id is still alive. If not, you can go ahead.
You can create a Server socket like
new ServerSocket(65535, 1, InetAddress.getLocalHost());
at very beginning of your code. Then if AddressAlreadyInUse exception caught in main block you can display the appropriate message.
There are already available java methods in File class to achieve the same. The method is deleteOnExit() which ensure the file is automatically deleted when the JVM exits. However, it does not cater to forcible terminations. One should use FileLock in case of forcible termination.
For more details check, https://docs.oracle.com/javase/7/docs/api/java/io/File.html
Thus code snippet which could be used in the main method can be like :
public static void main(String args[]) throws Exception {
File f = new File("checkFile");
if (!f.exists()) {
f.createNewFile();
} else {
System.out.println("App already running" );
return;
}
f.deleteOnExit();
// whatever your app is supposed to do
System.out.println("Blah Blah")
}
..what other mechanism could I use?
If the app. has a GUI it can be launched using Java Web Start. The JNLP API provided to web-start offers the SingleInstanceService. Here is my demo. of the SingleInstanceService.
You can write something like this.
If file exists try to delete it. if it is not able to delete. We can say that application is already running.
Now create the same file again and redirect the sysout and syserr.
This works for me
Simple lock and advanced lock
I developed 2 solutions for this problem. I was also looking for an easy way of doing this without using any libraries and a lot of code.
My solutions are based on: https://stackoverflow.com/a/46705579/10686802 which I have improved upon. Therefore I would like to thank #akshaya pandey and #rbento
Simple file lock
package YOUR_PACKAGE_NAME;
import java.io.File;
import java.io.IOException;
/**
* Minimal reproducible example (MRE) - Example of a simple lock file.
* #author Remzi Cavdar - ict#remzi.info - #Remzi1993
*/
public class Main {
public static void main(String[] args) {
/*
* Prevents the user of starting multiple instances of the application.
* This is done by creating a temporary file in the app directory.
* The temp file should be excluded from git and is called App.lock in this example.
*/
final File FILE = new File("App.lock");
try {
if (FILE.createNewFile()) {
System.out.println("Starting application");
} else {
System.err.println("The application is already running!");
return;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
/*
* Register a shutdown hook to delete the lock file when the application is closed. Even when forcefully closed
* with the task manager. (Tested on Windows 11 with JavaFX 19)
*/
FILE.deleteOnExit();
// Whatever your app is supposed to do
}
}
Advanced lock
package YOUR_PACKAGE_NAME;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
/**
* Minimal reproducible example (MRE) - Example of a more advanced lock system.
* #author Remzi Cavdar - ict#remzi.info - #Remzi1993
*/
public class Main {
public static void main(String[] args) {
/*
* Prevents the user of starting multiple instances of the application.
* This is done by creating a temporary file in the app directory.
* The temp file should be excluded from git and is called App.lock in this example.
*/
final File FILE = new File("App.lock");
if (FILE.exists()) {
System.err.println("The application is already running!");
return;
}
try (
FileOutputStream fileOutputStream = new FileOutputStream(FILE);
FileChannel channel = fileOutputStream.getChannel();
FileLock lock = channel.lock()
) {
System.out.println("Starting application");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
/*
* Register a shutdown hook to delete the lock file when the application is closed. Even when forcefully closed
* with the task manager. (Tested on Windows 11 with JavaFX 19)
*/
FILE.deleteOnExit();
// Whatever your app is supposed to do
}
}
Testing
Tested on: 31-10-2022
Tested OS: Windows 11 - Version 21H2 (OS Build 22000.1098)
Tested with: OpenJDK 19 - Eclipse Temurin JDK with Hotspot 19+36(x64)
I closed the application and also forcefully closed the application with task manager on Windows both times the lock file seems to be deleted upon (force) close.
I struggled with this same problem for a while... none of the ideas presented here worked for me. In all cases, the lock (file, socket or otherwise) did not persist into the 2nd process instance, so the 2nd instance still ran.
So I decided to try an old school approach to simply crate a .pid file with the process id of the first process. Then any 2nd process would quit if it finds the .pid file, and also the process number specified in the file is confirmed to be still running. This approach worked for me.
There is a fair bit of code, which I provide here in full for your use... a complete solution.
package common.environment;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.*;
import java.nio.charset.Charset;
public class SingleAppInstance
{
private static final #Nonnull Logger log = LogManager.getLogger(SingleAppInstance.class.getName());
/**
* Enforces that only a single instance of the given component is running. This
* is resilient to crashes, unexpected reboots and other forceful termination
* scenarios.
*
* #param componentName = Name of this component, for disambiguation with other
* components that may run simultaneously with this one.
* #return = true if the program is the only instance and is allowed to run.
*/
public static boolean isOnlyInstanceOf(#Nonnull String componentName)
{
boolean result = false;
// Make sure the directory exists
String dirPath = getHomePath();
try
{
FileUtil.createDirectories(dirPath);
}
catch (IOException e)
{
throw new RuntimeException(String.format("Unable to create directory: [%s]", dirPath));
}
File pidFile = new File(dirPath, componentName + ".pid");
// Try to read a prior, existing pid from the pid file. Returns null if the file doesn't exist.
String oldPid = FileUtil.readFile(pidFile);
// See if such a process is running.
if (oldPid != null && ProcessChecker.isStillAllive(oldPid))
{
log.error(String.format("An instance of %s is already running", componentName));
}
// If that process isn't running, create a new lock file for the current process.
else
{
// Write current pid to the file.
long thisPid = ProcessHandle.current().pid();
FileUtil.createFile(pidFile.getAbsolutePath(), String.valueOf(thisPid));
// Try to be tidy. Note: This won't happen on exit if forcibly terminated, so we don't depend on it.
pidFile.deleteOnExit();
result = true;
}
return result;
}
public static #Nonnull String getHomePath()
{
// Returns a path like C:/Users/Person/
return System.getProperty("user.home") + "/";
}
}
class ProcessChecker
{
private static final #Nonnull Logger log = LogManager.getLogger(io.cpucoin.core.platform.ProcessChecker.class.getName());
static boolean isStillAllive(#Nonnull String pidStr)
{
String OS = System.getProperty("os.name").toLowerCase();
String command;
if (OS.contains("win"))
{
log.debug("Check alive Windows mode. Pid: [{}]", pidStr);
command = "cmd /c tasklist /FI \"PID eq " + pidStr + "\"";
}
else if (OS.contains("nix") || OS.contains("nux"))
{
log.debug("Check alive Linux/Unix mode. Pid: [{}]", pidStr);
command = "ps -p " + pidStr;
}
else
{
log.warn("Unsupported OS: Check alive for Pid: [{}] return false", pidStr);
return false;
}
return isProcessIdRunning(pidStr, command); // call generic implementation
}
private static boolean isProcessIdRunning(#Nonnull String pid, #Nonnull String command)
{
log.debug("Command [{}]", command);
try
{
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec(command);
InputStreamReader isReader = new InputStreamReader(pr.getInputStream());
BufferedReader bReader = new BufferedReader(isReader);
String strLine;
while ((strLine = bReader.readLine()) != null)
{
if (strLine.contains(" " + pid + " "))
{
return true;
}
}
return false;
}
catch (Exception ex)
{
log.warn("Got exception using system command [{}].", command, ex);
return true;
}
}
}
class FileUtil
{
static void createDirectories(#Nonnull String dirPath) throws IOException
{
File dir = new File(dirPath);
if (dir.mkdirs()) /* If false, directories already exist so nothing to do. */
{
if (!dir.exists())
{
throw new IOException(String.format("Failed to create directory (access permissions problem?): [%s]", dirPath));
}
}
}
static void createFile(#Nonnull String fullPathToFile, #Nonnull String contents)
{
try (PrintWriter writer = new PrintWriter(fullPathToFile, Charset.defaultCharset()))
{
writer.print(contents);
}
catch (IOException e)
{
throw new RuntimeException(String.format("Unable to create file at %s! %s", fullPathToFile, e.getMessage()), e);
}
}
static #Nullable String readFile(#Nonnull File file)
{
try
{
try (BufferedReader fileReader = new BufferedReader(new FileReader(file)))
{
StringBuilder result = new StringBuilder();
String line;
while ((line = fileReader.readLine()) != null)
{
result.append(line);
if (fileReader.ready())
result.append("\n");
}
return result.toString();
}
}
catch (IOException e)
{
return null;
}
}
}
To use it, simply invoke it like this:
if (!SingleAppInstance.isOnlyInstanceOf("my-component"))
{
// quit
}
I hope you find this helpful.
Finally I found really simple library to achieve this. You can you use JUniqe.
The JUnique library can be used to prevent a user to run at the same
time more instances of the same Java application.
This is an example how to use it from the documentation
public static void main(String[] args) {
String appId = "myapplicationid";
boolean alreadyRunning;
try {
JUnique.acquireLock(appId);
alreadyRunning = false;
} catch (AlreadyLockedException e) {
alreadyRunning = true;
}
if (!alreadyRunning) {
// Start sequence here
}
}
here is a pretty rudimental approach.
If your application is launched from a script, check the running java/javaw processes and their command line before launch
In windows
REM check if there is a javaw process running your.main.class
REM if found, go to the end of the script and skip the launch of a new instance
WMIC path win32_process WHERE "Name='javaw.exe'" get CommandLine 2>nul | findstr your.main.class >nul 2>&1
if %ERRORLEVEL% EQU 0 goto:eof
javaw your.main.class