Unter Android (oder unter Linux generell) wird eine Leerzeile (als "EOF") geschrieben, nicht aber unter Windows?

Hallo zusammen

Der Code verwendet halt ein wenig Reflection und ein java.lang.Object für das eine Argument, weil ich das Zeugs ausserhalb von Android (mit einem kleinen JUnit-Test unter Eclipse / Win10) anschauen wollte. Des Weiteren wird die Funktion dadurch problemlos unter beiden Plattformen (Android & plattformunabhängig) einsetzbar.

Aber unter Android gibt’s ein Return am Ende, unter Windows hingegen nicht. Klar geht mein Hash-Vergleich (Password für das Android-App unter .../com.blabla/0/.pwdfile mit einem SHA-512 und dazu noch ein wenig „Security by obscurity“…;-)) damit quasi „in die Hose“, wenn in der Datei ne Leerzeile ist aber im Hash vom Password-Feld her (Gegenprüfung) nicht…

Code hier:

public static String writeFileOnInternalStorage(final Object caDirectoryOrAndroidAppContext, final String caFileNameWithOptionalRelativePath, final String caFileContent)
    {
        FileWriter lFileWriter = null;

        try
        {
            final String clObjectClassName = caDirectoryOrAndroidAppContext.getClass().getName();
            File lFile = null;

            if ((clObjectClassName.intern() == "android.app.Application") || (clObjectClassName.intern() == "android.content.Context"))
            {
                final Method clFilesDirMethod = caDirectoryOrAndroidAppContext.getClass().getMethod("getFilesDir");
                final File clFilesDir = (File) clFilesDirMethod.invoke(caDirectoryOrAndroidAppContext);
                lFile = new File(clFilesDir, "/");
                lFile = new File(lFile, caFileNameWithOptionalRelativePath);
            }
            else
            {
                if (caDirectoryOrAndroidAppContext instanceof String)
                {
                    final String clAbsolutFilePath = caDirectoryOrAndroidAppContext + File.separator + caFileNameWithOptionalRelativePath;
                    lFile = new File(clAbsolutFilePath);
                }
            }

            String lRetValPrefix = "File is already existing, was overwritten:";

            if (!lFile.exists())
            {
                if (caDirectoryOrAndroidAppContext instanceof String)
                {
                    lFile.createNewFile();
                }

                lRetValPrefix = "File didn't exist until now, was created:";
            }

            lRetValPrefix = lRetValPrefix + " ";
            lFileWriter = new FileWriter(lFile);
            lFileWriter.append(caFileContent);
            lFileWriter.flush();

            return lRetValPrefix + lFile.getAbsolutePath();

        }
        catch (final Exception caException)
        {
            return "Exception: " + caException.getMessage();
        }
        finally
        {
            if (lFileWriter != null)
            {
                try
                {
                    lFileWriter.close();
                }
                catch (final Exception caException)
                {
                    final Runtime clRuntime = Runtime.getRuntime();
                    clRuntime.gc();
                }
            }
        }
    }

Ich würde eher nur ungern sowas machen.

fileContent = fileContent.replace("\n", "").replace("\r", "");

Vielen Dank für die Feedbacks.

Habe es nun auch noch unter Windows getestet in dem ein Hash mit meinem Verfahren mitgegeben wird (damit es in dieser Hinsicht gleich ist wie unter Window$)

        System.out.println(PrintWriterEndOfFileProblem.writeFileOnInternalStorage("C:\\Users\\XXX", "TEST.txt", Hasher.hash("qwert", Hasher.SHA512)));

Ist gleich: Damit auch keine Leerzeile unter Window$…

Problem „gelöst“ mit:

final String clPasswordHashFromFile = StaticHelperClass.openFileOnInternalStorage(this.getApplicationContext(), ".pwdhash").replace("\r\n", "").replace("\r", "").replace("\n", "");

…zusätzlich noch „\r\n“ als sep. String bringt wohl nicht allzu viel, schadet aber sicher auch nicht! :wink:

na
nana

und

nanana

würde dann den gleichen Hash liefern :wink:

Danke, werde der Sache nachgehen; aber bitte nix mehr dazu verraten, warum, wieso und weshalb! ! :wink:

Also bei mir nicht wirklich:

			public void testPrintWriterEndOfFileProblem_na() {
		System.out.println("Test function testPrintWriterEndOfFileProblem_na(): write ... ");
		System.out.println(PrintWriterEndOfFileProblem.writeFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt",
				Hasher.hash("na", Hasher.SHA512)));
		
		System.out.println("Test function testPrintWriterEndOfFileProblem(): read ... ");
		final String clFileContent = PrintWriterEndOfFileProblem.openFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt").replace("\r\n", "").replace("\r", "").replace("\n", "");;
		System.out.println("File content: " + clFileContent);
	}

	
	public void testPrintWriterEndOfFileProblem_nana() {
		System.out.println("Test function testPrintWriterEndOfFileProblem_nana(): write ... ");
		System.out.println(PrintWriterEndOfFileProblem.writeFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt",
				Hasher.hash("nana", Hasher.SHA512)));
		
		System.out.println("Test function testPrintWriterEndOfFileProblem(): read ... ");
		final String clFileContent = PrintWriterEndOfFileProblem.openFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt").replace("\r\n", "").replace("\r", "").replace("\n", "");;
		System.out.println("File content: " + clFileContent);
	}
	
	public void testPrintWriterEndOfFileProblem_nanana() {
		System.out.println("Test function testPrintWriterEndOfFileProblem_nanana(): write ... ");
		System.out.println(PrintWriterEndOfFileProblem.writeFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt",
				Hasher.hash("nanana", Hasher.SHA512)));
		
		System.out.println("Test function testPrintWriterEndOfFileProblem(): read ... ");
		final String clFileContent = PrintWriterEndOfFileProblem.openFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt").replace("\r\n", "").replace("\r", "").replace("\n", "");;
		System.out.println("File content: " + clFileContent);
	}

Ausgabe:

Test function testPrintWriterEndOfFileProblem_nanana(): write ... 
File is already existing, was overwritten: C:\Users\xxx\TEST.txt
Test function testPrintWriterEndOfFileProblem(): read ... 
File content: 40946257f1f5653e361dc670a489e2face9e2b5e1858dba02cf840fb9bfaa5ef013182dafe8b89a2c4417139e30869e9da3554b1bb3bfe902e5e2b5c528e71b6
Test function testPrintWriterEndOfFileProblem_na(): write ... 
File is already existing, was overwritten: C:\Users\xxx\TEST.txt
Test function testPrintWriterEndOfFileProblem(): read ... 
File content: e2d0181ee3bb4a437c9b6a2358b08d7103b409ba202b75a4b1d9dca83ba8db0c9837ecc6f898f32a27ebb36367be0696ba5e095742c742cdc1fefbb8e8d7d21f
Test function testPrintWriterEndOfFileProblem_nana(): write ... 
File is already existing, was overwritten: C:\Users\xxx\TEST.txt
Test function testPrintWriterEndOfFileProblem(): read ... 
File content: 37bdf6dfe9b40ba59244bf86f2b6bfeca817ca5f8d35c74de629a9c8e50074fa96778559308443d3fe719fc6ae166aa56e69fad1cc81ad36bddc139c6f520d38

Aber du warst wohl etwas voreilig oder wolltest mich verulken? :slight_smile:
(Für Letzteres habe ich aber während der Arbeit nicht wirklich Zeit! ;-))

Gruss, Jan

Das Problem ist damit zwar nur umgangen, aber immerhin sind jetzt beide Funktionen writeFileOnInternalStorage(...) wie auch openFileOnInternalStorage(...) Android- wie auch zu „normalem“ (da Test ausserhalb von Android stattfanden aber sich dort eh anders verhielten) Java kompatibel… :+1: :+1: :+1:

(WTF, Google Chome unterstreicht mir Android im oberen Satz als falsch, LOL!! ROFL!!!)

Gruss, Jan

Sagen wir so, ich tippe gerade vom Handy aus, und da ist Quellcode etwas schwerlich in Gänze zu erfassen. Ich kann aber gerne später nochmal schauen, ob mir noch etwas auffällt; wenn ich soll. lg

Oh… Alles klar, sorry für die Vorverurteilung, tut mir leid!!

(Persönlich tue mit dem Handy eigentlich nur telefonieren und SMS schreiben - das einzige für was ich Internet brauche sind Zahlungen über den CH-Anbieter „TWINT“ sowie um über unsere „Smart Home“ / Gebäudesteuerungs-SW bei uns 2 Türen öffnen…)

Komisch ist einfach dass die Klasse mit File/FileWriter unter Android eine zusätzliche Leerzeile setzt („End of File“, EOF??), statt nur eine 1-Zeilen-Datei zu erstellen welche den Hash enthält.

Unter Windows gibt’s damit nur einen 1-Zeiler.

(???)

Aber eben, dann halt im Nachhinein „gerade biegen“… zwar nicht die Datei selbst, sondern den Hash-String den man aus dieser ausliest, indem man Zeile #2 einfach entfernt. (Wie bereits erwähnt über hashAusDateiInhalt.replace("\r\n", "").replace("\r", "").replace("\n", ""); … läuft soweit, und es muss ja, wie bei den meisten Chefs und nicht nur bei unserem, besser „vorgestern als morgen“ erledigt sein.

Kannst es anschauen wenn du willst (habe da nicht die geringste Erwartungshaltung), falls es dich im allgemeinen interessieren würde oder aber auch wenn du denkst dass du eines Tages auf das gleiche Problem stossen könntest. Oder wie auch immer… :wink:

Die Codes sind sicher nicht perfekt, funktionieren aber mal vorerst „nach aussen“:

Hier der Code zum schreiben:

public static String writeFileOnInternalStorage(final Object caDirectoryOrAndroidAppContext, final String caFileNameWithOptionalRelativePath, final String caFileContent)
    {
        FileWriter lFileWriter = null;

        try
        {
            final String clObjectClassName = caDirectoryOrAndroidAppContext.getClass().getName();
            File lFile = null;

            if ((clObjectClassName.intern() == "android.app.Application") || (clObjectClassName.intern() == "android.content.Context"))
            {
                final Method clFilesDirMethod = caDirectoryOrAndroidAppContext.getClass().getMethod("getFilesDir");
                final File clFilesDir = (File) clFilesDirMethod.invoke(caDirectoryOrAndroidAppContext);
                lFile = new File(clFilesDir, "/");
                lFile = new File(lFile, caFileNameWithOptionalRelativePath);
            }
            else
            {
                if (caDirectoryOrAndroidAppContext instanceof String)
                {
                    final String clAbsolutFilePath = caDirectoryOrAndroidAppContext + File.separator + caFileNameWithOptionalRelativePath;
                    lFile = new File(clAbsolutFilePath);
                }
            }

            String lRetValPrefix = "File is already existing, was overwritten:";

            if (!lFile.exists())
            {
                if (caDirectoryOrAndroidAppContext instanceof String)
                {
                    lFile.createNewFile();
                }

                lRetValPrefix = "File didn't exist until now, was created:";
            }

            lRetValPrefix = lRetValPrefix + " ";
            lFileWriter = new FileWriter(lFile);
            lFileWriter.append(caFileContent);
            lFileWriter.flush();

            return lRetValPrefix + lFile.getAbsolutePath();
        }
        catch (final Exception caException)
        {
            return "Exception: " + caException.getMessage();
        }
        finally
        {
            if (lFileWriter != null)
            {
                try
                {
                    lFileWriter.close();
                }
                catch (final Exception caException)
                {
                    final Runtime clRuntime = Runtime.getRuntime();
                    clRuntime.gc();
                }
            }
        }
    }

Hier der Code zum Lesen:

public static String openFileOnInternalStorage(final Object caDirectoryOrAndroidAppContext,
			final String caFileNameWithOptionalRelativePath) {
		BufferedReader lBufferedReader = null;
		final StringWriter clStringWriter = new StringWriter();

		final String clObjectClassName = caDirectoryOrAndroidAppContext.getClass().getName();

		try {
			File lFile = null;

			if ((clObjectClassName.intern() == "android.app.Application")
					|| (clObjectClassName.intern() == "android.content.Context")) {
				final Method clFilesDirMethod = caDirectoryOrAndroidAppContext.getClass().getMethod("getFilesDir");
				final File clFilesDir = (File) clFilesDirMethod.invoke(caDirectoryOrAndroidAppContext);
				lFile = new File(clFilesDir, "/");
				lFile = new File(lFile, caFileNameWithOptionalRelativePath);
			} else {
				if (caDirectoryOrAndroidAppContext instanceof String) {
					final String clAbsolutFilePath = caDirectoryOrAndroidAppContext + File.separator
							+ caFileNameWithOptionalRelativePath;
					lFile = new File(clAbsolutFilePath);
				}
			}

			lBufferedReader = new BufferedReader(new FileReader(lFile));
			String lLine = null;
			final String clLineSeparator = System.getProperty("line.separator");

			while ((lLine = lBufferedReader.readLine()) != null) {
				clStringWriter.append(lLine);
				clStringWriter.append(clLineSeparator);
			}

			return new String(clStringWriter.toString());
		} catch (final Exception caException) {
			return "Exception: " + caException.getMessage();
		} finally {
			try {
				if (clStringWriter != null) {
					clStringWriter.close();
				}

				if (lBufferedReader != null) {
					lBufferedReader.close();
				}
			} catch (final Exception clException) {
				final Runtime clRuntime = Runtime.getRuntime();
				clRuntime.gc();
			}
		}
	}

Hier der Einsatz als testPrefixJUnitTest-Methode (class … extends TestCase, die JUnit-Variante der alten Schule, ist aber einfach als Ersatz für ne main(…)-Funktion gedacht, d.h. ohne irgendwelche Unit-Test-typischen Sachen wie assert & Co…). Eigentlich noch mal das gleiche wie in einem vorherigen Post von mir:

			public void testPrintWriterEndOfFileProblem_na() {
		System.out.println("Test function testPrintWriterEndOfFileProblem_na(): write ... ");
		System.out.println(PrintWriterEndOfFileProblem.writeFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt",
				Hasher.hash("na", Hasher.SHA512)));
		
		System.out.println("Test function testPrintWriterEndOfFileProblem(): read ... ");
		final String clFileContent = PrintWriterEndOfFileProblem.openFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt").replace("\r\n", "").replace("\r", "").replace("\n", "");;
		System.out.println("File content: " + clFileContent);
	}

	
	public void testPrintWriterEndOfFileProblem_nana() {
		System.out.println("Test function testPrintWriterEndOfFileProblem_nana(): write ... ");
		System.out.println(PrintWriterEndOfFileProblem.writeFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt",
				Hasher.hash("nana", Hasher.SHA512)));
		
		System.out.println("Test function testPrintWriterEndOfFileProblem(): read ... ");
		final String clFileContent = PrintWriterEndOfFileProblem.openFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt").replace("\r\n", "").replace("\r", "").replace("\n", "");;
		System.out.println("File content: " + clFileContent);
	}
	
	public void testPrintWriterEndOfFileProblem_nanana() {
		System.out.println("Test function testPrintWriterEndOfFileProblem_nanana(): write ... ");
		System.out.println(PrintWriterEndOfFileProblem.writeFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt",
				Hasher.hash("nanana", Hasher.SHA512)));
		
		System.out.println("Test function testPrintWriterEndOfFileProblem(): read ... ");
		final String clFileContent = PrintWriterEndOfFileProblem.openFileOnInternalStorage("C:\\Users\\xxx", "TEST.txt").replace("\r\n", "").replace("\r", "").replace("\n", "");;
		System.out.println("File content: " + clFileContent);
	}

Resulat:

Test function testPrintWriterEndOfFileProblem_nanana(): write ... 
File is already existing, was overwritten: C:\Users\xxx\TEST.txt
Test function testPrintWriterEndOfFileProblem(): read ... 
File content: 40946257f1f5653e361dc670a489e2face9e2b5e1858dba02cf840fb9bfaa5ef013182dafe8b89a2c4417139e30869e9da3554b1bb3bfe902e5e2b5c528e71b6
Test function testPrintWriterEndOfFileProblem_na(): write ... 
File is already existing, was overwritten: C:\Users\xxx\TEST.txt
Test function testPrintWriterEndOfFileProblem(): read ... 
File content: e2d0181ee3bb4a437c9b6a2358b08d7103b409ba202b75a4b1d9dca83ba8db0c9837ecc6f898f32a27ebb36367be0696ba5e095742c742cdc1fefbb8e8d7d21f
Test function testPrintWriterEndOfFileProblem_nana(): write ... 
File is already existing, was overwritten: C:\Users\xxx\TEST.txt
Test function testPrintWriterEndOfFileProblem(): read ... 
File content: 37bdf6dfe9b40ba59244bf86f2b6bfeca817ca5f8d35c74de629a9c8e50074fa96778559308443d3fe719fc6ae166aa56e69fad1cc81ad36bddc139c6f520d38

…scheint demzufolge zu gehen, alle Hashes sind anders; habe das Problem mit der Leerzeile ja ausserhalb von Android testen wollen, als Anfänger habe ich mühe das dort zu debuggen. Deshalb geben die Funktionen auch Strings zurück, welche ich zumindest mit einer Android-MessageBox anzeigen könnte.

Deshalb JUnit-Test unter Windows. Aber dort tritt dann plötzlich das Problem mit der 2. Leerzeile nicht mehr auf.

Was auch die Kernfrage des Threads ist.

Bei der Sache mit den Hashes mit na/nana/nanana-Kennwörtern und hashAusDateiInhalt.replace("\r\n", "").replace("\r", "").replace("\n", ""); läuft alles glatt! :-))

Gruss, Jan

Nachtrag: „PrintWriter“ in den Namen ist falsch, hab da was verwechselt… wenn schon: „FileWriter“

Vorurteile (eigentlich: spricht man in der Psychologie nur von Urteilen und Entscheidungen, denn wenn ich mir ein Vorurteil gebildet habe, dann habe ich schon geurteilt) hat jeder Mensch, es ist nur die Frage, wie sehr diese ausgelebt werden können - oder diese unterdrückt werden müssen - oder wie laissez-faire bzw. „restringiert“ man damit umgeht.

Die höchste Form menschlicher Intelligenz ist die Fähigkeit, zu beobachten ohne zu bewerten.
- Jiddu Krishnamurti

… folglich bin ich dir überhaupt nicht böse.

@CyborgBeta: Alles klar, danke fürs Feedback!! :wink:

Zurück zum Thema: Evtl. wüsste sonst noch jemand was zu diesem Thema Mit Leerzeile auf Android (und ggf. anderen Linux-Systemen) oder ohne Leerzeile (Zumindest auf Window$ festgestellt) bei der File/FileWriter-Kombination…?

Vielen Dank für die Feedbacks.

Allgemeines Feedback? Willst du das wirklich?

Ja, ich will...

Beim kurzen Drüberschauen:

  • Der Versuch, in den Methoden „alle möglichen Konfigurationen“ mit vielen Klassennamen-Vergleichen abzuhandeln ist sicher keine gute Idee. Wenn ein Variablenname caDirectoryOrAndroidAppContext ist (d.h. ein „oder“ enthält), ist das schon eine Rote Flagge, auf die die UdSSR stolz gewesen wäre)

  • Was soll das mit der Reflection dort? Autsch…

  • Was soll der Effekt von zwei unmittelbar aufeinanderfolgenden Zeilen
    lFile = new File(clFilesDir, "/");
    lFile = new File(lFile, caFileNameWithOptionalRelativePath);
    sein?

  • Lass’ die final bei lokalen Variablen weg

  • Mach’ nicht sowas wie catch (Exception ...). Fange, was geworfen wird. Und kratze dich da, wo es juckt.

  • Rufe nie runtime.gc() auf. (System.gc() wäre einfacher, aber auch das sollte man nie aufrufen)

  • Rufe nie einString.intern() auf

  • Vergleiche nie strings mit ==.

  • Wenn in wenigen Zeilen mehrmals ein grausliger String wie "C:\\Users\\xxx" vorkommt, ist schon was faul. („Bei mir geht das nicht …“)

  • Wenn das replaceAll... sowieso immer gemacht werden muss, warum machst du es dann nicht in der Methode?

Ich befürchte, dass irgendwann mal Leute solchen Code lesen, und dann glauben, Java wäre eine schlechte Programmiersprache… :frowning:

Was auch immer du da machst: Du verstehst es nicht. Nichtmal ansatzweise. Und dass andere den Code lesen, nachvollziehen, das Problem erkennen (und nachvollziehen) und die Ursache des Problems identifzieren (und ggf. auch eine Lösung finden) können, ist recht viel verlangt.

Ich hab’ jetzt mal geschaut, und möchte anfangen mit der Frage…

Warum nicht einfach so?
    package bytewelt.lineendings;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    
    
    public class LineEndingsTestBasic
    {
        public static void main(String[] args) throws IOException
        {
            testPrintWriterEndOfFileProblem_na();
            testPrintWriterEndOfFileProblem_nana();
            testPrintWriterEndOfFileProblem_nanana();
            
        }
        
        public static String writeFileOnInternalStorage(
            Context context, String fileName, String content) throws IOException
        {
            File filesDir = context.getFilesDir();
            Path fullPath = filesDir.toPath().resolve(fileName);
            writeFile(fullPath, content);
            return "Done"; // Whatever...
        }
        public static String writeFileOnInternalStorage(
            String baseDirName, String fileName, String content) throws IOException
        {
            Path fullPath = Paths.get(baseDirName, fileName);
            writeFile(fullPath, content);
            return "Done"; // Whatever...
        }
    
        public static String openFileOnInternalStorage(
            Context context, String fileName) throws IOException
        {
            File filesDir = context.getFilesDir();
            Path fullPath = filesDir.toPath().resolve(fileName);
            return readFile(fullPath);
        }
    
        public static String openFileOnInternalStorage(
            String baseDirName, String fileName) throws IOException
        {
            Path fullPath = Paths.get(baseDirName, fileName);
            return readFile(fullPath);
        }
    
        private static void writeFile(Path path, String content) throws IOException
        {
            try (FileWriter fileWriter = new FileWriter(path.toFile()))
            {
                fileWriter.write(content);
                fileWriter.flush();
            }
        }
        
        private static String readFile(Path path) throws IOException
        {
            StringBuilder sb = new StringBuilder();
            String lineSeparator = System.getProperty("line.separator");
            try (BufferedReader br = new BufferedReader(
                new FileReader(path.toFile())))
            {
                boolean firstLine = true;
                while (true)
                {
                    String line = br.readLine();
                    if (line == null)
                    {
                        break;
                    }
                    if (!firstLine)
                    {
                        sb.append(lineSeparator);
                    }
                    firstLine = false;
                    sb.append(line);
                }
            }
            return sb.toString();
        }
        
        
        //=========================================================================
        // Test stuff below this line...
        
        
        static class Context
        {
            File getFilesDir()
            {
                return new File(".");
            }
        }
        
        static class Hasher
        {
            public static Object SHA512 = null;
    
            public static String hash(String string, Object sHA5122)
            {
                return "Batman";
            }
        }
        
        public static void testPrintWriterEndOfFileProblem_na() throws IOException
        {
            System.out.println(
                "Test function testPrintWriterEndOfFileProblem_na(): write ... ");
            System.out.println(writeFileOnInternalStorage(".",
                "TEST.txt", Hasher.hash("na", Hasher.SHA512)));
    
            System.out.println(
                "Test function testPrintWriterEndOfFileProblem(): read ... ");
            final String clFileContent =
                openFileOnInternalStorage(".", "TEST.txt")
                    .replace("\r\n", "").replace("\r", "").replace("\n", "");
            System.out.println("File content: " + clFileContent);
        }
    
        public static void testPrintWriterEndOfFileProblem_nana() throws IOException
        {
            System.out.println(
                "Test function testPrintWriterEndOfFileProblem_nana(): write ... ");
            System.out.println(writeFileOnInternalStorage(".",
                "TEST.txt", Hasher.hash("nana", Hasher.SHA512)));
    
            System.out.println(
                "Test function testPrintWriterEndOfFileProblem(): read ... ");
            final String clFileContent =
                openFileOnInternalStorage(".", "TEST.txt")
                    .replace("\r\n", "").replace("\r", "").replace("\n", "");
            System.out.println("File content: " + clFileContent);
        }
    
        public static void testPrintWriterEndOfFileProblem_nanana() throws IOException
        {
            System.out.println(
                "Test function testPrintWriterEndOfFileProblem_nanana(): write ... ");
            System.out.println(writeFileOnInternalStorage(".",
                "TEST.txt", Hasher.hash("nanana", Hasher.SHA512)));
    
            System.out.println(
                "Test function testPrintWriterEndOfFileProblem(): read ... ");
            final String clFileContent =
                openFileOnInternalStorage(".", "TEST.txt")
                    .replace("\r\n", "").replace("\r", "").replace("\n", "");
            System.out.println("File content: " + clFileContent);
        }
    }

Konkreter auf das Problem bezogen: Man liest sowas dann, und versucht, es einzurodnen, und stolpert in diesem Prozess des „Aufräumens“ (der schon fast „mechanisch“ ist - wie die Straße zu kehren oder sich die Zähne zu putzen) über sowas hier:

        while ((lLine = lBufferedReader.readLine()) != null)
        {
            clStringWriter.append(lLine);
            clStringWriter.append(clLineSeparator);
        }

Dort wird eine Datei gelesen, die ggf. nur eine Zeile (ohne abschließenden line.separator!!!) enthält, und diese Zeile wird dann in einen String geschrieben, und (bedingungslos!) ein line.separator angehängt - denn du dann mit einen abstrusen replaceAll-Verrenkungen wieder entfernst.

Ich weiß (natürlich) nicht, ob das „DIE URSACHE“ für das Problem ist, aber in der obigen („aufgeräumten“) Version steht jetzt mal als „Alternativvorschlag“

boolean firstLine = true;
while (true)
{
    String line = br.readLine();
    if (line == null)
    {
        break;
    }
    if (!firstLine)
    {
        sb.append(lineSeparator);
    }
    firstLine = false;
    sb.append(line);
}

(auch gleich mit einem StringBuilder und nicht mit einem StringWriter).

Der Punkt ist: Ein line.separator wird nach einer Zeile angehängt, wenn danach auch wirklich eine weitere Zeile kommt.

Könnte das schon die Lösung sein?

(EDIT, als keiner Nachtrag: Mit sowas wie Files.readAllLines oder Collectors.joining könnte man diesen Block ggf. auch als zweizeiler schreiben, aber da muss man dann über Android-Capabilities nachdenken, und … es geht ja erstmal nur darum, rauszufinden, was das Problem ist, und wie man es lösen könnte)

1 „Gefällt mir“

"Könnte das schon die Lösung sein?"

Ja, vielen Dank…