• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Jeanne Boyarsky
  • Bear Bibeault
  • Knute Snortum
  • Liutauras Vilda
Sheriffs:
  • Tim Cooke
  • Devaka Cooray
  • Paul Clapham
Saloon Keepers:
  • Tim Moores
  • Frits Walraven
  • Ron McLeod
  • Ganesh Patekar
  • salvin francis
Bartenders:
  • Tim Holloway
  • Carey Brown
  • Stephan van Hulst

Replace a string in a text file with user input  RSS feed

 
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi everyone! : ))

I am currently trying to replace a word in a text file with another word that the user types in the console and then print the updated content of the text file onto the console.
I am stuck right now with this task. Could someone be so kind to point out what I am doing wrong here?
Thanks a lot!

My code:

 
Master Rancher
Posts: 915
17
Firefox Browser Hibernate IntelliJ IDE Java MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Welcome to the ranch, always post your stacktrace, when you have one...
It's not enough to read the file and replace the word, you also have to write it back to the file
 
Bartender
Posts: 5303
55
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Line 24 is VERY BAD. NEVER EVER close a scanner created from System.in.

Lines 30 and 31 are swapped. You want to use the FileReader as input to BufferedReader.

Your use of String#replaceAll() on line 33 will get you into trouble because the first argument to the method is a regular expression, not a simple string. So any special regex characters in 'input' will cause it to misbehave.
 
Bartender
Posts: 20124
103
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Carey Brown wrote:Line 24 is VERY BAD. NEVER EVER close a scanner created from System.in.



Oh?

First, how are you supposed to distinguish between a scanner created on System.in as a console, System.in as a piped-in stream/file, and a scanner that can be created on an arbitrary source? That's a lot of coupling there.

It's a fairly reliable rule that when you close a high-level input source, that the close operation will cascade and close its parent sources. And, in fact, the JavaDocs explicitly state that if the superior readable implements Closeable, that this is what will happen. So if System.in doesn't want to be closed, then all it has to do is refuse to implement Closeable.

However, in fact, it's common practice to close stdin (which is the basis for System.in) in programs. There is, in fact a possibility that failing to close when there is unconsumed data could cause that data to hang around in buffers and pollute downstream processes, depending on the OS implementation. Also, if an app is attempting to read too far, that's a state violation, and it's better that such offenses be detected and reported. Which is what should happen when you try to read a closed input source.

If you're using System.in as a heterogeneous data source where you only feed a few lines to the scanner and send the remaining input somewhere else (perhaps even a different scanner), then it would be appropriate not to close the Scanner and simply let it drop out of scope, but this isn't a common practice, and it needs to be done with care and reference to the underlying buffer contents.

Also, in Java, if you close() an object more that once that's usually OK. So if you close a scanner and then close the file that the scanner consumes from that's not an error.

Finally, a Scanner can be built in a try-with-resources environment and close that way as well.
 
Carey Brown
Bartender
Posts: 5303
55
Eclipse IDE Firefox Browser Java MySQL Database VI Editor Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Output:
 
Marshal
Posts: 5633
147
Chrome Eclipse IDE Java Postgres Database VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you close a Scanner object based on System.in, you will not be able to use System.in afterwards.
 
Marshal
Posts: 62231
193
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Agree with Knute and Carey, but that isn't going to help OP with his current problem.

OP: Haven't you been taught try with resources? It is a far better way to close resources because it ensures the resource will be closed irrespective of whether the preceding code does or doesn't throw an exception. And as you doubtless know, you must close all resources used, except System.in, System.out and System.err. The way you use System.out and system.err, there is rarely any temptation to close them, but Eclipse gives you warnings about not closing Scanners reading System.in. This is one of those instances where you have to be circumspect about the warning; I usually choose Eclipse's option to mark the code with @SuppressWarnings("unused"). One of the few places where @SupporessWarnings is appropriate. Remember, other sorts of resource can be opened repeatedly, but not System.in, etc. I notice you aren't closing the buffered reader.
Now, your reading code is a bit confused. You are doing exactly the same in the two catches in lines 10 and 12, so why not combine them into one, remembering that IOException is a superclass of FileNotFoundException. Also, what do lines 7‑q4 do? I think the most they will do is verify the existence of the file.
Don't use classes whose names end Stream for text files; use classes whose names end Reader. You might be able to use a file input stream to read text all in ASCII, but as soon as you encounter a char > 0x7f in a UTF‑file or similar, the input stream will be unable to cope.
You have got lines 30‑31 the wrong way round; you will be passing null ot the buffered reader constructor, and that won't actually read anything. You will probably get a null pointer exception somewhere, but I am not certain.
You are correctly reading the lines from the file in line 33, but not doing anything with it:-
  • 1: Because Strings are immutable, the replaceAll() call doesn't modify the String; it create a new String, which you aren't using.
  • 2: You are not working with the line from the file; the s variable is a separate copy, so ay changes there are not reflected back to the file.
  • As far as I know, you can't change a single line in a text file like that. You might be able to do omething similar in a random access file, which you can read about in the Java™ Tutorials somewhere. But I think you are going to have to do something like this:-
  • 1: Read the lines from file1.
  • 2: Make any changes and create Strings representing the new text.
  • 3: Write the altered lines to file2.
  • 4: Rename file2.
  • Do the reading and writing line by line. You should be able to find the details of that sort of thing from the same Java™ Tutorials link.

    What follow might be an advanced topic only suitable for the ambitious programmer.
    You can also do the reading with a Stream<String> which you get from the Buffered Reader's lines() method.
     
    Tim Holloway
    Bartender
    Posts: 20124
    103
    Android Eclipse IDE Linux
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator

    Knute Snortum wrote:If you close a Scanner object based on System.in, you will not be able to use System.in afterwards.



    Tim Holloway wrote:
    If you're using System.in as a heterogeneous data source where you only feed a few lines to the scanner and send the remaining input somewhere else (perhaps even a different scanner), then it would be appropriate not to close the Scanner and simply let it drop out of scope, but this isn't a common practice, and it needs to be done with care and reference to the underlying buffer contents.



    But actually for the problem in question, a Scanner seems like overkill and replace would be my choice, but leveraging the fact that replace is based on regexes instead of being victimized by it.

    That is:


    The first change I made was to define "pattern" as the input string as being the text word input (please note Carey's admonition. If the user inputs something that isn't a word (contains non-alphameric characters), then the match may behave in unexpected ways.  So I wrapped the (presumed) word with the regex pattern character for non-word context (beginning/end of line, whitespace, punctuation, etc.). And since the backslash is a String escape character, I had to write two of them to get the effect of one backslash at runtime.

    I then changed the string replace to use that pattern. AND I assigned the results. It's important to note that String replace is not an inline operation (and since Strings in Java are immutable, it couldn't be). Instead the replace operation returns an entirely new String!
     
    Willie Smits can speak 40 languages. This tiny ad can speak only one:
    RavenDB is an Open Source NoSQL Database that’s fully transactional (ACID) across your database
    https://coderanch.com/t/704633/RavenDB-Open-Source-NoSQL-Database
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!