I'm new to java and I'm having a little problem with my code. There's no error and such, it just keeps saying process finished but no output was displayed. The filename is correct as I've checked.
import java.nio.file.;
import java.io.;
public class GuessingGame {
public GuessingGame() {
String filename = "C:\\Users\\angela\\Documents\\words.txt";
Path path = Paths.get(filename.toString());
try {
InputStream input = Files.newInputStream(path);
BufferedReader read = new BufferedReader(new InputStreamReader(input));
String word = null;
while((word = read.readLine()) !=null) {
System.out.println(word);
}
}
catch(IOException ex) {
}
}
public static void main (String[] args) {
new GuessingGame();
}
}
You are ignoring the exception and you don't close the file. Save some typing by using the built-in input.transferTo() for copying the file to System.out, and pass on the exception for the caller to handle by adding throws IOException to constructor and main.
Replace your try-catch block with this try-with-resources, which handles closing the file after use:
try (InputStream input = Files.newInputStream(path)) {
input.transferTo(System.out) ;
}
You managed to call the intended class, but you also needed to specify the specific function which you have declared in the function. Like so:
public static void main (String[] args) { GuessingGame gg = new GuessingGame; gg.GuessingGame(); }
Note: I am aware there are several questions similar to this one, however, I cannot find any which explain how to resolve the situation I am trying to resolve. I will ask this question with a specific example, for which I need a solution.
Consider the code:
private final void writeToFile(final File parent, final String filename, final Charset charset, final String content) throws IOException {
final File file = new File(parent, filename);
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.", file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.", file.getCanonicalPath()), null);
}
}
try (final FileOutputStream fos = new FileOutputStream(file);
OutputStreamWriter writer = new OutputStreamWriter(fos, charset)) {
writer.write(content);
}
}
I am trying to write a unit test to provoke the IOException being thrown when the code cannnot delete the file. The unit test I have tried is as follows:
#Test public void testFileNotDeletable() throws IOException {
final File file = new File(folder.getRoot(), formattedFile.getMetaData().getFormattedCaptureFileName());
file.createNewFile();
try {
file.setReadOnly();
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
writer.write(formattedFile);
} finally {
file.setWritable(true);
}
}
I have also tried locking the file:
#Test public void testFileNotDeletable() throws IOException {
final File file = new File(folder.getRoot(), formattedFile.getMetaData().getFormattedCaptureFileName());
file.createNewFile();
try (FileInputStream fis = new FileInputStream(file)) {
final FileLock lock = fis.getChannel().tryLock(0L, Long.MAX_VALUE, true);
try {
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
writer.write(formattedFile);
} finally {
lock.release();
}
}
}
No matter what I try, the file.delete() successfully deletes the file, and the test fails, as the expected IOException was not thrown.
Any help greatly appreciated.
Note: Added for clarification, some extra code that shows that the File object is completely separate in the environments. The formattedFile being passed to the write method is not a File or sub-class of File, it is one of our internal classes. The File in the JUnit test is using a TemporaryFolder for the root, the formattedFile has a MetaData item, which determines the filename. In my JUnit test I am trying to create an empty file, which cannot be deleted, in the location that my actual code will attempt to write the file. I need file.delete() to return false, so that I can test the exception is being thrown. I therefore cannot mock a File object.
There are two solutions to your question, I recommend the first one.
Solution 1
You are not testing the java file I/O operations/class here, you are testing your code's functional behaviour in response to file operation. So, ideally in your JUnit you should be mocking the File object & its respective calls, and only focus on testing your code.
Solution 2
If you still wish to test full integration with java file IO, open file in write mode before attempting to delete, and it will take care of your test case.
NOTE: Code tested in CENTOS, WINDOWS, UBUNTU, MAC OS-X
Subject Class:
public class FileSolution {
public void fileHandler(File file) throws IOException, Exception {
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.",
file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.",
file.getCanonicalPath()),
new IOException(String.format("Cannot delete file '%s'.",
file.getCanonicalPath())));
}
}
}
}
Subject Uner Test:
import static org.mockito.BDDMockito.*;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
public class FileSolutionTest {
#Rule
public final ExpectedException exception = ExpectedException.none();
/**
* Solution 1
*
* #throws Exception
*/
#Test
public void testFileNotDeletableWithMock() throws Exception {
final File file = mock(File.class);
file.createNewFile();
// mock file & IO operations
given(file.exists()).willReturn(true);
given(file.delete()).willReturn(false);
given(file.getCanonicalPath()).willReturn("test.txt");
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
new FileSolution().fileHandler(file);
}
/**
* Solution 2
*
* #throws Exception
*/
#Test
public void testFileNotDeletable() throws Exception {
File file = null;
FileWriter fileWriter = null;
try{
file = new File("test.txt");
file.createNewFile();
file.deleteOnExit();
exception.expect(IOException.class);
exception.expectMessage(String.format("Cannot delete file '%s'.", file.getCanonicalPath()));
// open file with another process for writing
fileWriter = new FileWriter(file, true);
new FileSolution().fileHandler(file);
} finally{
if(fileWriter != null){
fileWriter.flush();
fileWriter.close();
}
}
}
}
I totally agree with Turing85 about using mockito.
Let's imagine you have an original class with a method similar to the one you want to test:
public class FileDel {
public void logOnIOException(File file) throws IOException {
if (file.exists()) {
LOG.warn("File {} already exists, file will be replaced.", file.getCanonicalPath());
if (!file.delete()) {
logAndThrow(String.format("Cannot delete file '%s'.", file.getCanonicalPath()), null);
}
}
}
public void logAndThrow(String msg, String s) {
//Do nothing
}
private static class LOG {
public static void warn(String msg, String path) {
}
}
}
Then you can trigger an inner exception in this way:
#RunWith(MockitoJUnitRunner.class)
public class FileDelTest {
#Test(expected = IOException.class)
public void testFileNotDeletable() throws IOException {
File file = mock(File.class);
when(file.exists()).thenReturn(true);
when(file.delete()).thenAnswer(new Answer<Boolean>() {
#Override
public Boolean answer(InvocationOnMock iom) throws Throwable {
throw new IOException();
}
});
FileDel f = new FileDel();
try {
f.methodToTest(file);
} finally {
}
}
}
What about open InputStream for this file and do not close it. Until file's descriptor will not be closed, file will not be deleted.
In order to prevent a file from being deleted you have to deny the security permission in windows. From the UI we would need to do something like
Right-click the file or document in your PC => Choose Properties;
In Security, tab Edit to change permission => Select Add and enter Everyone;
Press OK and select the group to change Full control permission to Deny;
Press Yes to confirm.
The only way I know of to change file permissions with Java are:
file.setExecutable(true|false);
file.setReadable(true|false);
file.setWritable(true|false);
and
File file = new File("test.txt");
if(file.exists())
{
//Setting file permissions for owner, group and others using PosixFilePermission
HashSet<PosixFilePermission> set = new HashSet<PosixFilePermission>();
//Adding owner's file permissions
set.add(PosixFilePermission.OWNER_EXECUTE);
set.add(PosixFilePermission.OWNER_READ);
set.add(PosixFilePermission.OWNER_WRITE);
//Adding group's file permissions
set.add(PosixFilePermission.GROUP_EXECUTE);
set.add(PosixFilePermission.GROUP_READ);
set.add(PosixFilePermission.GROUP_WRITE);
//Adding other's file permissions
set.add(PosixFilePermission.OTHERS_EXECUTE);
set.add(PosixFilePermission.OTHERS_READ);
set.add(PosixFilePermission.OTHERS_WRITE);
Files.setPosixFilePermissions(Paths.get("test.txt"), set);
}
else
{
System.out.println("Sorry...File doesn't exist.");
}
So, preventing a file from being deleted I would assume would have to do with file writing permissions. Try disabling the writable and maybe the executable permissions before trying to delete the file.
If this doesn't work then I do not believe it can be done with the Java language yet as these are the only methods available at the moment for changing file permissions. I could be wrong, but I have been unable to find anything else.
UPDATE
For Linux try the following:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class ExecuteShellComand {
public static void main(String[] args) {
ExecuteShellComand obj = new ExecuteShellComand();
String command = "sudo chattr +i /backups/passwd";
// OR try
//String command = "sudo chattr +i -V /backups/passwd";
String output = obj.executeCommand(command);
System.out.println(output);
}
private String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
The above makes /backups/passwd file immutable (or undeletable). This implies that the file can’t be modified in any way: it can’t be deleted or renamed. You can’t even create a link to it and no data can be written to the file as well.
That's about the only thing I can think of.
Hope this helps.
In Linux you can, with the chattr command set a file that is "immutable" that cannot be deleted even by root. Someone else said "set file permissions" which is right, but did not give specific detail.
Cheers
D
I am trying to read a .txt file and search for a word, but the program just closes with Process finished with exit code 0.
import java.io.*;
import java.util.ArrayList;
import java.util.Scanner;
public class LogParser {
static Scanner file;
static ArrayList text = new ArrayList();
static String path = new String();
static String check = new String();
private static int a = 0;
static Scanner inpunt = new Scanner(System.in);
public static void main (String[] args) {
System.out.println("Input path to file");
path = inpunt.nextLine();
File texts = new File(path);
try {
file = new Scanner(new File(path));
} catch (Exception e) {
System.out.println("Can't open file");
}
try {
while (file.hasNext()) {
text.add(a, file.nextLine());
check = text.get(a).toString();
if (check.contains("cap"))
System.out.println("Allert!!!!!!!!!!!!!!!!!!!!!!!!!!!" + text.get(a));
a = a + 1;
}
} catch (Exception e) {
// System.out.println("Can't open file");
if (file.toString().contains("cap"))
System.out.println("cap" + "Path to file: " + path);
System.out.println(text.size());
}
}
}
The text in the .txt file is:
let's try read this cap
If I try to open an xml file, everything is ok. My problem is only in txt files.
As mentioned in the comments, your path variable isn't set. You're trying to create a new file and passing in a path that hasn't been instantiated.
I am trying to write code for a word guessing game, and it works well when I use bufferedreader and inputstream combined. But when I try it using scanner, it cannot find the file, even though in both instances the file is in the same folder. It is in a folder called res under the src folder in my project folder(I am coding in eclipse).
import java.util.ArrayList;
import java.util.Scanner;
import java.io.File;
public class WordGen {
private final String filename = "/res/words.txt";
File file = new File(filename);
Scanner input = null;
private ArrayList<String> list = new ArrayList<>();
public WordGen() {
try {
input = new Scanner(file);
while (input.hasNextLine()) {
String w = input.nextLine();
list.add(w);
}
} catch (Exception ex) {
System.out.println("File not found.");
}
}
public String getword() {
if (list.isEmpty()) {
return "NOTHING";
}
return list.get((int) (Math.random() * list.size()));
}
}
public class test {
public static void main(String[] args) {
WordGen wordgen = new WordGen();
System.out.println(wordgen.getword());
}
}
I tried searching for this problem but couldn't find it here. I am guessing it's a very small error which I cannot figure out. Thanks and regards.
EDIT: Here's the other code that worked(Everything else same as before):
public WordGenerator()
{
try(InputStream input = getClass().getResourceAsStream(fileName);
BufferedReader bfreader = new BufferedReader(new InputStreamReader(input)))
{
String line = "";
while ((line = bfreader.readLine()) != null)
words.add(line);
}
catch (Exception e)
{
System.out.println("Couldn't find file");
}
}
Scanner is trying to load a file - and you're providing an absolute filename, /res/words.txt.
In order to create an InputStream, you're loading a resource, giving it an absolute resource name, even though you've called the variable fileName:
getClass().getResourceAsStream(fileName)
That works because it can load a resource called /res/words.txt from the classpath, but it's not loading a file with a filename of /res/words.txt.
You could use a filename of res/words.txt, if you run the code from the src directory... or you could just stick to using getResourceAsStream, which is probably a better idea as it doesn't rely on your working directory, and will continue to work even if your code and resources are packaged up into a jar file.
If you really want to use Scanner, you could always use new Scanner(input) - there's a Scanner constructor accepting an InputStream.
My problem is that whenever I run my program from Eclipse or IntelliJ I can create as many files in a specific folder but when I create a jar it only creates one file no matter how many times I call the method that does this.
In detail a feature of a program allows the user to create a file in the folder where the jar is executed from. This is done through a class containing static fields and methods.
The fields in the class are:
private static StringBuilder sb = new StringBuilder();
private static Formatter formatter = new Formatter(sb);
private static BufferedWriter bw;
private static String filesFolderPath;
First I get the path to the jar:
private static String getJarPath() throws UnsupportedEncodingException
{
URL url = PrintHelper.class.getProtectionDomain().getCodeSource().getLocation();
String jarPath = URLDecoder.decode(url.getFile(), "UTF-8");
String path = new File(jarPath).getParentFile().getPath();
return path;
}
Then I set the path to the folder I want the files to be put in and create that folder through a static block in the class so that this code is executed only once when the class is first used:
static
{
try
{
String dirPath = getJarPath();
String fileSeparator = System.getProperty("file.separator");
filesFolderPath = dirPath + fileSeparator + "files" + fileSeparator;
File file = new File(filesFolderPath);
file.mkdir();
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
}
Finally. each time a user wants to create a file this method is called:
public static void print(String filename) throws IOException, FileNotFoundException
{
File file = new File(filesFolderPath, getFileName(filename));
bw = new BufferedWriter(new FileWriter(file));
//writing with the buffered writer
bw.close();
}
Is there any reason for this to work as I want it when run from an IDE and create only one file when running from the jar?