[java]in txt bestand regel zoeken en veranderen

Pagina: 1
Acties:
  • 171 views sinds 30-01-2008
  • Reageer

  • Invalid
  • Registratie: September 2001
  • Niet online
Ik ben bezig met een progje dat in een tekst bestand een bepaalde regel opzoekt om vervolgens die regel te veranderen en het bestand weer (onder dezelfde naam) op te slaan.

Het opzoeken lukt me wel, maar het vervangen en opslaan niet. Wat ik nu heb is dat het progje:
1. een BufferedReader stream van het bestand opent en daarna een PrintWriter stream van hetzelfde bestand opent
2. de te veranderen regel opzoekt via een lusje met daarin readLine()
3. na het gevonden te hebben die regel veranderen met println van de PrintWriter.

Maar wat ik dan krijg is een leeg bestand! Dat is natuurlijk niet de bodoeling.

Kort samengevat: hoe kan in een bestand tegelijkertijd lezen en schrijven om uiteindelijk het bewerkte bestand onder de oude naam op te slaan?

Alvast bedankt!

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Kijk maar eens naar java.io.RandomAccessFile.

Met readers, writers, inputstreams en outputstream is random access (lezen en schrijven tegelijk) niet mogelijk.

Het kan ook met de nieuwe IO API's (java.nio) in 1.4.0 beta 3. Dit is wel erg stoer, maar ik neem maar even aan dat dit nog iets te vroeg is voor je ;) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Verduidelijking: als je hetgene wat jij wilt implementeren met readers en writers moet je de hele file inlezen en daarna de hele file wegschrijven.

Overigens moet je voor dit werk nooit de PrintWriter gebruiken: dit is een simpele wrapper rond een writer die alle foutmeldingen negeert...
Methods in this class never throw I/O exceptions. The client may inquire as to whether any errors have occurred by invoking checkError().

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Invalid
  • Registratie: September 2001
  • Niet online
Aha RandomAccessFile. Daar hoef ik er dus maar 1 van te openen en daarmee kan ik lezen en schrijven tegelijk?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Als je de lees-in -> pas-aan -> schrijf-weg aanpak wilt gebruiken:
InvalidTarget: Daar was ik al bang voor.Eerst het hele bestand regel voor regel inlezen, ergens in het geheugen opslaan
Inlezen van een file in een lijst van regels is hier al heel regelmatig ter sprake gekomen... Om precies te zijn gisteren nog :) : [topic=352303]
dan veranden
Je hebt gewoon een List van Strings in handen. Die is triviaal aan te passen...
en wegschrijven.
Wegschrijven is ook al vaak voorgedaan en gaat bijna hetzelfde als inlezen :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Invalid
  • Registratie: September 2001
  • Niet online
Inlezen van een file in een lijst van regels is hier al heel regelmatig ter sprake gekomen... Om precies te zijn gisteren nog.
Haha ik zie het. En elke thread verwijs je naar een vorige :)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
InvalidTarget: Aha RandomAccessFile. Daar hoef ik er dus maar 1 van te openen en daarmee kan ik lezen en schrijven tegelijk?
Yep

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
InvalidTarget: Haha ik zie het. En elke thread verwijs je naar een vorige :)
Hehe ;) . Het is inderdaad een vrij vaak voorkomend probleem.

Overigens kan dit probleem wel onwijs goed met nio ( :9~ ) worden opgelost... RandomAccess is daarbij vergeleken complete zooi :o .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Invalid
  • Registratie: September 2001
  • Niet online
Op dinsdag 18 december 2001 23:04 schreef mbravenboer het volgende:

[..]

Hehe ;) . Het is inderdaad een vrij vaak voorkomend probleem.

Overigens kan dit probleem wel onwijs goed met nio ( :9~ ) worden opgelost... RandomAccess is daarbij vergeleken complete zooi :o .
Ik ben nu die docs een beetje aan het doorbladeren. Kun je me ff in de goeie richting wijzen? Naar welke nieuwe class ik moet kijken bijv.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
InvalidTarget: Ik ben nu die docs een beetje aan het doorbladeren. Kun je me ff in de goeie richting wijzen? Naar welke nieuwe class ik moet kijken bijv.
FileChannel, MappedByteBuffer, CharBuffer ...

Je kunt ook even naar een leuke demo kijken. Deze is te vinden in /docs/guide/nio/example/Grep.java . Ze hebben daar het bekende Grep geimplementeerd met nio. Je kunt daar zijn hoe je een FileChannel opent en werkt met MappedByteBuffers.

Als je het graag wilt gebruiken, maar het niet allemaal even goed lukt kan ik wel even een voorbeeld maken (heb alleen zelf nog niet echt veel met nio gewerkt, dus kan ff duren ;) ).

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Invalid
  • Registratie: September 2001
  • Niet online
Op dinsdag 18 december 2001 23:12 schreef mbravenboer het volgende:
Als je het graag wilt gebruiken, maar het niet allemaal even goed lukt kan ik wel even een voorbeeld maken (heb alleen zelf nog niet echt veel met nio gewerkt, dus kan ff duren ;) ).
Grep.java heb ik al lang gezien. Dat is behoorlijk ingewikkeld (voor mijn java niveau). Maar wat ik eruit begrijp is dat het niet helemaal aansluit op mijn probleem. (zoeken, veranderen en opslaan)

Maar als jij een voorbeeldje wil maken: graag! Maar houd het aub heel simpel: hij zoekt een bestandje door op een bep. regel. Als ie die gevonden heeft overschrijft ie die met een andere regel en slaat het op.

Alvast bedankt! (8>

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
InvalidTarget: Grep.java heb ik al lang gezien. Dat is behoorlijk ingewikkeld (voor mijn java niveau). Maar wat ik eruit begrijp is dat het niet helemaal aansluit op mijn probleem. (zoeken, veranderen en opslaan)
Het Grep voorbeeld doet alleen maar een een zoek-aktie, maar je kan die MappedByteBuffers ook in read-write mode openen. Dan kan je ze dus ook aanpassen :) .
Maar als jij een voorbeeldje wil maken: graag! Maar houd het aub heel simpel: hij zoekt een bestandje door op een bep. regel. Als ie die gevonden heeft overschrijft ie die met een andere regel en slaat het op.
Ik ben al wat aan het bakken :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Oeps, dit gaat niet werken helaas :( . Ik lees dat er een zware bug in 1.4.0 beta 3 zit waardoor alle charbuffer toestanden niet werken |:( . Je zult het dan helaas toch met RandomAccessFile of read -> modify -> write moeten oplossen.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

En er staan hier ook nog een aantal string replace routines ;)

  • Invalid
  • Registratie: September 2001
  • Niet online
Op dinsdag 18 december 2001 23:59 schreef mbravenboer het volgende:
Oeps, dit gaat niet werken helaas :( . Ik lees dat er een zware bug in 1.4.0 beta 3 zit waardoor alle charbuffer toestanden niet werken |:( . Je zult het dan helaas toch met RandomAccessFile of read -> modify -> write moeten oplossen.
Aha, maar wat dacht u van een voorbeeldje van randomaccessfile? :)

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
InvalidTarget: Aha, maar wat dacht u van een voorbeeldje van randomaccessfile? :)
Haha, grapjas :+ .

Als je nu een zelf in de Java Tutorial naar The Really Big Index was gegaan, had je dit onderdeel gevonden. Samen met de API docs moet het makkelijk lukken :* .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Invalid
  • Registratie: September 2001
  • Niet online
Dat had ik ook wel gevonden, maar daar staan geen voorbeeldjes... ik zal maar wat gaan prutsen en kijken of ik het werkend kan krijgen...

  • Invalid
  • Registratie: September 2001
  • Niet online
Het spijt me maar ik kom er toch niet uit. Ik heb de docs gelezen en heb nu dit in elkaar geprutst (ik gebruik hier een tekst bestandje met 10 regels waarop de getallen 1 t/m 10):
code:
1
2
3
4
5
6
7
RandomAccessFile f = new RandomAccessFile(args[0], "rw");
String l;
while((l = f.readLine()) != null) {
    if(l.equals("5")) {
        f.writeChars("dit is regel 5");
    }
}

Dit werkt helaas niet. De volgende dingen gaan fout:
1. De regel word NA de regel met 5 geschreven
2. De geschreven regel blijkt voor elk karakter nog een karakter te hebben (heeft vast iets te maken met unicode <-> ascii
4. Alle regels na deze geschreven regels zijn verwijderd

Tips? Hints?

Alvast bedankt

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Nou vooruit ik zal ff kijken of ik een voorbeeldje kan maken ;) .

RandomAccessFile heb ik ook heel lang niet meer gebruikt, dus ik zie zo het probleem helaas niet.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Hum het probleem is vrij ernstig :o .

Ik had er helemaal niet aan gedacht |:( : als je write worden de bytes op de file pointer overschreven... Als er dus nog flink wat tekst na komt zul je zien dat er nog wel wat blijft staan.

Ik heb je denk ik behoorlijk de verkeerde kant uitgestuurd, want om dit op te lossen moet je alle bytes gaan opschuiven, wat wel te doen is, maar niet bepaald triviaal.

Misschien dat je het beste toch maar de hele file kunt inlezen een list van strings, deze manipuleren en daarna wegschrijven.

De lees code heb je al, de write code kan ik je eventueel ook geven.

Sorry :o .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Invalid
  • Registratie: September 2001
  • Niet online
Wat ik nou vreemd vind is dat hier geen standaard methode voor blijkt te zijn (of ik kan hem niet vinden). Het lezen en schrijven naar tekst bestanden komt toch vaak voor zou ik zo denken. Denk bijv. aan configuratie bestanden...

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Yep, maar ja: waar naar wil je hem inlezen? Iedereen heeft op dit punt andere wensen. Een library moet altijd beslissen wat generiek is en wat niet. Bij de Java libs kiezen ze er vaak voor om geen aannames te maken.... in tegenstelling tot bijvoorbeeld PHP.

Als het trouwens ook mogelijk is om naar een andere file weg te schrijven dan diegene waar uit je leest, dan heb ik nog een hele mooie oplossing voor je liggen die je heel eenvoudig kan toepassen. Eventueel kan je dan achteraf de oude file verwijderen en de nieuwe hernoemen...

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Omdat ik het toch wel een beetje sneu vond dat ik je zo de verkeerde kant op had gestuurd, heb ik maar even een oplossing voor je geimplementeerd. Hij bartst van de design-patterns, is toch redelijk simpel en is heel erg goed te hergebruiken. Ook gaat hij erg efficient om met geheugen en kan daardoor alle grote files aan.

Allereerst heb ik een read methode die de elke regel doorgeeft aan een 'ContentHandler'. Deze ContentHandler kan iets met de String gaan doen: opslaan in een structuur zoals een List of bijvoorbeeld zoals ik ga doen vervangen door een andere regel of wegschrijven naar een file.

Dit is de code:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.*;

public class XFileReader
{
    public void read(File file, ContentHandler handler) throws IOException, FileNotFoundException, ContentHandleException
    {
        BufferedReader reader = new BufferedReader(new FileReader(file));

        String s;
        boolean proceed = true;
     
        while((s = reader.readLine())!=null && proceed)
        {
            proceed = handler.handle(s);
        }
      
        reader.close();
    }
}

redelijke simpel he?

Dit is de ContentHandler:
code:
1
2
3
4
public interface ContentHandler
{
    public boolean handle(String line) throws ContentHandleException;
}

Nu kan je de ContentHandler op veel verschillende manieren implementeren. Je kunt bijvoorbeeld een ContentHandler maken die de regel gelijk weer wegschrijft naar een andere file:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.io.IOException;
import java.io.Writer;

public class WritingContentHandler implements ContentHandler
{
    private Writer writer;

    public WritingContentHandler(Writer writer)
    {
        super();
        this.writer = writer;
    }

    public boolean handle(String line) throws ContentHandleException
    {
        try
        {
            writer.write(line);
            writer.write('\n');
            return true;
        }
        catch(IOException exc)
        {
            throw new ContentHandleException("Couldn't write line: " + line , exc);
        }
    }
}

Als je een file gaat lezen via de XFileReader en daarbij deze ContentHandler meegeeft zul je zien dat hij gewoon de file kopieert.

Zoals je ziet gebruik ik nog een Exception:
code:
1
2
3
4
5
6
7
8
9
10
11
12
public class ContentHandleException extends Exception
{
    public ContentHandleException(String message, Exception exc)
    {
        super(message, exc);
    }

    public ContentHandleException(String message)
    {
        super(message);
    }
}

Als je geen 1.4.0 gebruikt moet je even de Exception uit de constructor halen (en uiteraard ook niet meegeven in de WritingContentHandler).

Maar goed, kopieren willen we niet: bepaalde regels moeten vervangen worden. Daarom schrijven we een replacer:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class SimpleReplacingContentHandler implements ContentHandler
{
    private ContentHandler next;
    private String firstline;
    private String replacement;

    public SimpleReplacingContentHandler(ContentHandler next, String line, String replacement)
    {
        super();
        this.next = next;
        this.firstline = line;
        this.replacement = replacement;
    }

    public boolean handle(String line) throws ContentHandleException
    {
        String newline;

        if(line.equals(firstline))
        {
            newline = replacement;
        }
        else
        {
            newline = line;
        }

        return next.handle(newline);
    }
}

Deze ContentHandler is in feite een tussenlaag: hij heeft de line weer door aan een volgende ContentHandler. Hij vervangt echter bepaalde regels zoals je kunt aangeven in de constructor.

Als je nu aan de SimpleReplacingContentHandler een WritingContentHandler meegeeft en hiermee een File gaat inlezen, heb je precies wat jij wil!

Ik heb een kleine applicatie gemaakt om het te testen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.*;

public class Application
{
    public static void main(String[] ps)
    {
      try
        {
            File source = new File(ps[0]);
            File target = new File(ps[1]);

            Writer writer = new BufferedWriter(new FileWriter(target));

            ContentHandler contentHandler = new SimpleReplacingContentHandler(
                new WritingContentHandler(writer),
                "Dit is een te vervangen regel!",
                "Dit is de vervanging");

            new XFileReader().read(source, contentHandler);

            writer.flush();
            writer.close();
      }
      catch(Exception exc)
      {
         exc.printStackTrace();
      }
    }
}

Als ik nu deze input neem:
code:
1
2
3
4
5
6
7
Test voorbeeld
Dit is een te vervangen regel!
Boeh
Bah
Dit is een te vervangen regel!
Dit is een te vervangen regel!ha
Boeh

komt er keurig dit uit:
code:
1
2
3
4
5
6
7
Test voorbeeld
Dit is de vervanging
Boeh
Bah
Dit is de vervanging
Dit is een te vervangen regel!ha
Boeh

Dit is dus precies wat je wilde :) . Ik hoop dat je het tot nu toe allemaal snapt en kunt toepassen :) .

Om even aan te tonen hoe makkelijk deze aanpak is, heb ik nog even een vervanger met reguliere expressies gemaakt. Als je geen 1.4.0 hebt, zal deze niet compileren.
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class RegexReplacingContentHandler implements ContentHandler
{
    private ContentHandler next;
    private Pattern pattern;
    private String replacement;

    public RegexReplacingContentHandler(ContentHandler next, String regex, String replacement)
    {
        super();
        this.next = next;
        this.pattern = Pattern.compile(regex);
        this.replacement = replacement;
    }

    public boolean handle(String line) throws ContentHandleException
    {
        Matcher matcher = pattern.matcher(line);
        String newline = matcher.replaceAll(replacement);

        return next.handle(newline);
    }
}

deze kan je aanroepen met deze applicatie:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.*;

public class RegexApplication
{
    public static void main(String[] ps)
    {
      try
        {
            File source = new File(ps[0]);
            File target = new File(ps[1]);

            Writer writer = new BufferedWriter(new FileWriter(target));

            ContentHandler contentHandler = new RegexReplacingContentHandler(
                new WritingContentHandler(writer),
                "Dit is een te vervangen regel!",
                "Dit is de vervanging");

            new XFileReader().read(source, contentHandler);

            writer.flush();
            writer.close();
      }
      catch(Exception exc)
      {
         exc.printStackTrace();
      }
    }
}

Uiteraard is de gekozen reguliere expressies hier niet zo spannend, maar het gaat maar even om het voorbeeld :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Invalid
  • Registratie: September 2001
  • Niet online
edit:

domme vraag :)
Pagina: 1