Android escribiendo registros en el archivo de texto

128

Estoy tratando de escribir registros en el archivo Log.txt personalizado en el archivo de Android usando este código mío, pero luego este método crea un archivo pero no contiene nada. Básicamente, quiero leer el contenido anterior del archivo y luego agregar mis datos con el contenido existente.

El código es el siguiente :

public static void write(String str) 
    {
        InputStream fileInputStream = null;
        FileOutputStream fileOutpurStream = null;
        try
        { 
            fileInputStream = new FileInputStream(file);
            fileOutpurStream = new FileOutputStream(file);
            if(file.exists())
            {
                int ch = 0;
                int current = 0;
                StringBuffer buffer = new StringBuffer();
                while((ch = fileInputStream.read()) != -1)
                {
                    buffer.append((char) ch);
                    current++;
                }
                byte data[]=new byte[(int)file.length()];
                fileInputStream.read(data);   
                fileOutpurStream.write(data);
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            } 
            else
            {   
                file.createNewFile();
                fileOutpurStream.write(str.getBytes(),0,str.getBytes().length);
                fileOutpurStream.flush();
            }
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                fileInputStream.close();
                fileOutpurStream.flush();
                fileOutpurStream.close();
                fileOutpurStream = null;
                fileInputStream = null;
            }
            catch (IOException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
y ramesh rao
fuente

Respuestas:

247

Espero que esto pueda ayudar ...

public void appendLog(String text)
{       
   File logFile = new File("sdcard/log.file");
   if (!logFile.exists())
   {
      try
      {
         logFile.createNewFile();
      } 
      catch (IOException e)
      {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }
   try
   {
      //BufferedWriter for performance, true to set append to file flag
      BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true)); 
      buf.append(text);
      buf.newLine();
      buf.close();
   }
   catch (IOException e)
   {
      // TODO Auto-generated catch block
      e.printStackTrace();
   }
}
Outkkast
fuente
82
¡No olvides agregar permiso para escribir_almacenamiento_externo en Manifiesto!
virusss8
55
Tenía que agregar buf.flush (); beforebuf.close (); pero esta función era exactamente lo que necesitaba. gracias
Csabi
1
¿desde dónde debo llamar a esta función para que escriba el archivo de inicio de sesión de todas las aplicaciones?
uniruddh
10
Recomendaría reestructurar el código para que buf.close()esté dentro de un finallybloque.
William Price
2
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />era lo que @ virusss8 quería decir, por supuesto.
Bengt
29

Para aquellos nuevos en el registro de Java en general y el registro de Android

  1. Log4j es una implementación genérica de registro de Java y ahora es un proyecto de la fundación de software Apache. No es específico de Android y, por lo tanto, tiene algunas incompatibilidades con Android.
  2. SL4J no es una implementación de registro, es una capa de abstracción. Ayuda a evitar situaciones como, cada dependencia de la biblioteca de terceros a un proyecto, tratando de usar su propia implementación de registro como Log4j. Fuente .

Algunas opciones para iniciar sesión en txt en Android están a continuación

  1. Use logcat -fcomo en esta respuesta para iniciar sesión en el archivo. Tenga en cuenta que desde Android 4.2, el permiso READ_LOGS no tiene ningún impacto y cada aplicación (a menos que el teléfono esté rooteado) solo puede leer sus propios registros. La desventaja aquí es que el buffer logcat es circular y tiene un límite de tamaño. Es posible que no obtenga registros anteriores.
  2. Use microlog4android (escrito para dispositivos móviles como Android) como en la respuesta anterior . Podría haber una manera, pero no pude entender, cómo usar microlog4Android para iniciar sesión en el almacenamiento interno de la aplicación. La única opción para la ruta de registros era el almacenamiento externo como sdcard, por lo que no pude usarlo.
  3. Utilice Log4j con android-logging-log4j . ¿Qué hace android-logging-log4j? Hace que Log4j sea más fácil de usar en Android al proporcionar dos funciones.

    • opción de enviar registros a logcat además del archivo de registro
    • Una forma sencilla de configurar las opciones de configuración de Log4j como la ruta del archivo, el tamaño máximo del archivo, el número de copias de seguridad, etc., proporcionando la clase LogConfigurator.

    Ejemplo simple a continuación. Observe que el loggerobjeto en el siguiente ejemplo es un objeto Log4j devuelto y no una clase android-logging-log4j. Entonces, android-logging-log4j se usa solo para configurar Log4j.

  4. Sin embargo, para probar LogBack . LogBack es desarrollado por la misma persona que creó las bibliotecas Log4J 1.xy SL4J. Sin embargo, no está relacionado con Log4j 2.x.

Pasos para usar Log4j en Android.

  1. Agregue log4j-1.2.x.jar y android-logging-log4j-1.0.3.jar a la carpeta libs.

  2. Agregue permisos solo si usa almacenamiento externo
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  3. Escribir Log4jclase auxiliar

    package com.example.logger;
    
    import android.os.Environment;
    import de.mindpipe.android.logging.log4j.LogConfigurator;
    
    public class Log4jHelper {
        private final static LogConfigurator mLogConfigrator = new LogConfigurator();
    
        static {
            configureLog4j();
        }
    
        private static void configureLog4j() {
            String fileName = Environment.getExternalStorageDirectory() + "/" + "log4j.log";
            String filePattern = "%d - [%c] - %p : %m%n";
            int maxBackupSize = 10;
            long maxFileSize = 1024 * 1024;
    
            configure( fileName, filePattern, maxBackupSize, maxFileSize );
        }
    
        private static void configure( String fileName, String filePattern, int maxBackupSize, long maxFileSize ) {
            mLogConfigrator.setFileName( fileName );
            mLogConfigrator.setMaxFileSize( maxFileSize );
            mLogConfigrator.setFilePattern(filePattern);
            mLogConfigrator.setMaxBackupSize(maxBackupSize);
            mLogConfigrator.setUseLogCatAppender(true);
            mLogConfigrator.configure();
    
        }
    
        public static org.apache.log4j.Logger getLogger( String name ) {
            org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger( name );
            return logger;
        }
    }
    
  4. En clase de actividad

    org.apache.log4j.Logger log= Log4jHelper.getLogger( "YourActivity" );
    log.error("Error");
    log.info("Info");
    log.warn("Warn");
    

Fuente de ejemplo . Tenga en cuenta que log4j 2.x (funcionalidades mejoradas) reescrito desde cero no es compatible con log4j 1.x. Entonces debe usar log4j 1.2.x jar con android-logging-log4j jar. Pude iniciar sesión en el archivo interno de la aplicación y luego enviar el archivo por correo electrónico consetReadable(true, false)

Kiran
fuente
24

microlog4android funciona para mí, pero la documentación es bastante pobre. Todo lo que necesitan agregar es un tutorial de inicio rápido .

Aquí hay un tutorial rápido que encontré.

  1. Agregue la siguiente variable estática en su Actividad principal:

    private static final Logger logger = LoggerFactory.getLogger();
  2. Agregue lo siguiente a su onCreate()método:

    PropertyConfigurator.getConfigurator(this).configure();
  3. Cree un archivo llamado microlog.propertiesy guárdelo en el assetsdirectorio

  4. Edite el microlog.propertiesarchivo de la siguiente manera:

    microlog.level=DEBUG
    microlog.appender=LogCatAppender;FileAppender
    microlog.formatter=PatternFormatter
    microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
  5. Agregue declaraciones de registro como esta:

    logger.debug("M4A");

Para cada clase, crea un objeto registrador como se especifica en 1)

6.Puede agregar el siguiente permiso:

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

Aquí está la fuente del tutorial

Henry Bennett
fuente
44
FileAppender creará un archivo "microlog.txt" en su tarjeta sd (la ruta completa en mi caso es "/sdcard/microlog.txt).
Ruslan Yanchyshyn
2
Este tutorial rápido debería formar parte de la documentación oficial de Microlog4Android.
Johan Karlsson
Error: Android Dex: [proyecto] com.android.dex.DexException: Múltiples archivos dex definen Lcom / google / code / microlog4android / Level; ?
10

Advertencia: puedo estar malinterpretándote totalmente, pero si todo lo que quieres es un archivo de registro, ¿por qué sudar?

Ponga esto en un archivo bat (cambie la ruta a su directorio de herramientas, y yourappname es, por supuesto, el nombre de su aplicación):

cd "C:\devAndroid\Software\android-sdk-windows-1.6_r1\android-sdk-windows-1.6_r1\tools"
adb logcat -v time   ActivityManager:W  yourappname:D  *:W >"C:\devAndroid\log\yourappname.log"

Luego, en su código, simplemente haga algo similar a esto:

Log.d("yourappname", "Your message");

Para crear el registro, conecte el cable USB y ejecute su archivo bat.

Saludos

BeMeCollective
fuente
No olvides importar android.util.Log.
Spidey
Devuelve "error: más de un dispositivo y emulador - esperando dispositivo -" y nada más. ¿Tienes algo mal?
eros
20
¿Cómo funciona esto si no estás cerca de una PC mientras ejecutas la aplicación?
DDSports
@DDSports no lo hace. Pero no entendía la esencia de la pregunta
Ewoks el
@DDSports puedes usar adb a través de wifi.
Daniel F
8

Utilice slf4android lib.
Es una implementación simple de slf4j api usando android java.util.logging. *.

caracteristicas:

  • iniciar sesión para archivar fuera de la caja
  • iniciando sesión en cualquier otro destino por LoggerConfiguration.configuration().addHandlerToLogger
  • agite su dispositivo para enviar registros con captura de pantalla por correo electrónico
  • realmente pequeño, solo toma ~ 55kB

slf4android es mantenido principalmente por @miensol .

Lea más sobre slf4android en nuestro blog:

klimat
fuente
7

Deberías echar un vistazo a microlog4android. Tienen una solución lista para iniciar sesión en un archivo.

http://code.google.com/p/microlog4android/

Darius
fuente
12
Esto parece una buena biblioteca, pero la documentación es terrible. Simplemente no podía entender cómo hacer que funcione y terminé armando algo yo mismo.
Paul Lammertsma
@PaulLammertsma: Creo que sería bueno que contribuyeras con Microlog4Android. FYI: tiene la misma API que Log4j. Perdón por la mala documentación.
Johan Karlsson
@Paul Lammertsma ¿Cómo podría ALGO ser bueno si su documentación es tan mala que no puedes usarla? Si no puedes hacer que funcione, es una mierda.
El increíble Jan
7

Esto puede ser tarde, pero espero que esto pueda ayudar ... Intenta esto ...

public void writefile()
    {
        File externalStorageDir = Environment.getExternalStorageDirectory();
        File myFile = new File(externalStorageDir , "yourfilename.txt");

        if(myFile.exists())
        {
           try
           {

        FileOutputStream fostream = new FileOutputStream(myFile);
        OutputStreamWriter oswriter = new OutputStreamWriter(fostream); 
        BufferedWriter bwriter = new BufferedWriter(oswriter);   
        bwriter.write("Hi welcome ");
        bwriter.newLine();            
        bwriter.close(); 
        oswriter.close(); 
        fostream.close();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }
        else
        {
            try {
                myFile.createNewFile();
            }
            catch (IOException e) 
            {
                e.printStackTrace();
            }
        }

Aquí bfwritter.newlineescribe su texto en el archivo. Y agrega el permiso

 <uses-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"/>

en su archivo de manifiesto sin falta.

AndroidOptimist
fuente
6

Resolví este problema con el siguiente fragmento de código en la línea de comandos:

File outputFile = new File("pathToFile"); 
Runtime.getRuntime().exec("logcat -c");
Runtime.getRuntime().exec("logcat -v time -f " + outputFile.getAbsolutePath())

Donde la opción "hora" agrega detalles de campo de metadatos para la fecha, hora de invocación, prioridad / etiqueta y PID del proceso que emite el mensaje.

Luego, en su código, simplemente haga algo similar a esto (usando android.util.Log):

Log.d("yourappname", "Your message");
Estrella nueva
fuente
44
Funciona bien cuando adbestá conectado, pero no funciona cuando el dispositivo está en modo independiente. No lo usaría en producción, pero es una solución simple en modo de depuración.
Julien Kronegg
2

En general, debe tener un identificador de archivo antes de abrir la secuencia. Tiene un identificador fileOutputStream antes de createNewFile () en el bloque else. La secuencia no crea el archivo si no existe.

No es realmente específico de Android, pero eso es mucho IO para este propósito. ¿Qué pasa si haces muchas operaciones de "escritura" una tras otra? Leerá todo el contenido y escribirá todo el contenido, tomando tiempo y, lo que es más importante, la duración de la batería.

Sugiero usar java.io.RandomAccessFile, buscar () 'hasta el final, luego escribirChars () para agregar. Será un código mucho más limpio y probablemente mucho más rápido.

Nate
fuente
2

He creado una clase simple y liviana (alrededor de 260 LoC) que extiende la implementación estándar de android.util.Log con registro basado en archivos:
cada mensaje de registro se registra a través de android.util.Log y también se escribe en un archivo de texto en el dispositivo.

Puede encontrarlo en github:
https://github.com/volkerv/FileLog

Volker Voecking
fuente
1
¿no crees que necesitamos asegurarnos de que las operaciones de archivo no se realicen en el hilo de la interfaz de usuario? En caso de que tengamos una gran cantidad de registro de archivos?
Jayshil Dave
2

Después de mucho tiempo de investigación descubrí que:

  • android.util.Log por defecto uso java.util.logging.Logger
  • LogCat usa loggercon nombre "", para obtener una instancia de usoLogManager.getLogManager().getLogger("")
  • Los dispositivos Android se agregan a la loggerinstancia de LogCat com.android.internal.logging.AndroidHandlerdespués de la ejecución de aplicaciones de depuración
  • ¡¡¡Pero!!! com.android.internal.logging.AndroidHandlerimprime mensajes en logcat solo con niveles más java.util.logging.Level.INFO, como ( Level.INFO, Level.WARNING, Level.SEVERE, Level.OFF)

Entonces, para escribir registros en un archivo simplemente rootLogger "" agregue un java.util.logging.FileHandler:

  class App : Application{
    override fun onCreate() {
      super.onCreate()
      Log.d(TAG, printLoggers("before setup"))

      val rootLogger = java.util.logging.LogManager.getLogManager().getLogger("")
      val dirFile = destinationFolder
      val file = File(dirFile,"logFile.txt")
      val handler = java.util.logging.FileHandler(file.absolutePath, 5* 1024 * 1024/*5Mb*/, 1, true)
      handler.formatter = AndroidLogFormatter(filePath = file.absolutePath)

      rootLogger?.addHandler(handler)

      Log.d(TAG, printLoggers("after setup"))
    }
  }

val destinationFolder: File
        get() {
            val parent = 
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absoluteFile
            val destinationFolder = File(parent, "MyApp")
            if (!destinationFolder.exists()) {
                destinationFolder.mkdirs()
                destinationFolder.mkdir()
            }
            return destinationFolder
        }
class AndroidLogFormatter(val filePath: String = "", var tagPrefix: String = "") : Formatter() {

    override fun format(record: LogRecord): String {
        val tag = record.getTag(tagPrefix)
        val date = record.getDate()
        val level = record.getLogCatLevel()
        val message = record.getLogCatMessage()
        return "$date $level$tag: $message\n"
    }
}

fun LogRecord.getTag(tagPrefix: String): String {
    val name = loggerName
    val maxLength = 30
    val tag = tagPrefix + (if (name.length > maxLength) name.substring(name.length - maxLength) else name)
    return tag
}

fun LogRecord.getDate(): String? {
    return Date(millis).formatedBy("yyyy-MM-dd HH:mm:ss.SSS")
}

fun Date?.formatedBy(dateFormat: String): String? {
    val date = this
    date ?: return null
    val writeFormat = SimpleDateFormat(dateFormat, Locale.getDefault()) //MM в HH:mm
    return writeFormat.format(date)
}

fun LogRecord.getLogCatMessage(): String {
    var message = message

    if (thrown != null) {
        message += Log.getStackTraceString(thrown)
    }
    return message
}

fun Int.getAndroidLevel(): Int {
    return when {
        this >= Level.SEVERE.intValue() -> { // SEVERE
            Log.ERROR
        }
        this >= Level.WARNING.intValue() -> { // WARNING
            Log.WARN
        }
        this >= Level.INFO.intValue() -> { // INFO
            Log.INFO
        }
        else -> {
            Log.DEBUG
        }
    }
}

fun LogRecord.getLogCatLevel(): String {
    return when (level.intValue().getAndroidLevel()) {
        Log.ERROR -> { // SEVERE
            "E/"
        }
        Log.WARN -> { // WARNING
            "W/"
        }
        Log.INFO -> { // INFO
            "I/"
        }
        Log.DEBUG -> {
            "D/"
        }
        else -> {
            "D/"
        }
    }
}

fun getLoggerLevel(level: Int): Level {
    return when (level) {
        Log.ERROR -> { // SEVERE
            Level.SEVERE
        }
        Log.WARN -> { // WARNING
            Level.WARNING
        }
        Log.INFO -> { // INFO
            Level.INFO
        }
        Log.DEBUG -> {
            Level.FINE
        }
        else -> {
            Level.FINEST
        }
    }
}

Para imprimir todos los registradores en su aplicación, use:

Log.e(TAG, printLoggers("before setup"))

 private fun printLoggers(caller: String, printIfEmpty: Boolean = true): String {
        val builder = StringBuilder()
        val loggerNames = LogManager.getLogManager().loggerNames
        builder.appendln("--------------------------------------------------------------")
        builder.appendln("printLoggers: $caller")
        while (loggerNames.hasMoreElements()) {
            val element = loggerNames.nextElement()
            val logger = LogManager.getLogManager().getLogger(element)
            val parentLogger: Logger? = logger.parent
            val handlers = logger.handlers
            val level = logger?.level
            if (!printIfEmpty && handlers.isEmpty()) {
                continue
            }
            val handlersNames = handlers.map {
                val handlerName = it.javaClass.simpleName
                val formatter: Formatter? = it.formatter
                val formatterName = if (formatter is AndroidLogFormatter) {
                    "${formatter.javaClass.simpleName}(${formatter.filePath})"
                } else {
                    formatter?.javaClass?.simpleName
                }
                "$handlerName($formatterName)"
            }
            builder.appendln("level: $level logger: \"$element\" handlers: $handlersNames parentLogger: ${parentLogger?.name}")
        }
        builder.appendln("--------------------------------------------------------------")
        return builder.toString()
    }
NickUnuchek
fuente
Hola. ¿Cuál es el beneficio de usar este "" registrador? No veo diferencia con un registrador personalizado. O me estoy perdiendo algo ?
Abins Shaji
1

Esta variante es mucho más corta.

tratar {
    ruta final del archivo = nuevo archivo (
            Environment.getExternalStorageDirectory (), "DBO_logs5");
    if (! path.exists ()) {
        path.mkdir ();
    }
    Runtime.getRuntime (). Exec (
            "logcat -d -f" + ruta + File.separator
                    + "dbo_logcat"
                    + ".txt");
} catch (IOException e) {
    e.printStackTrace ();
}
xoxol_89
fuente
1

Puedes usar la biblioteca que he escrito. Es muy fácil de usar:

Agregue esta dependencia a su archivo gradle:

dependencies {
    compile 'com.github.danylovolokh:android-logger:1.0.2'
}

Inicialice la biblioteca en la clase Aplicación:

File logsDirectory = AndroidLogger.getDefaultLogFilesDirectory(this);
    int logFileMaxSizeBytes = 2 * 1024 * 1024; // 2Mb
    try {
        AndroidLogger.initialize(
                this,
                logsDirectory,
                "Log_File_Name",
                logFileMaxSizeBytes,
                false
                );
    } catch (IOException e) {
        // Some error happened - most likely there is no free space on the system
    }

Así es como usas la biblioteca:

AndroidLogger.v("TAG", "Verbose Message");

Y así es como recuperar los registros:

AndroidLogger.processPendingLogsStopAndGetLogFiles(new AndroidLogger.GetFilesCallback() {
        @Override
        public void onFiles(File[] logFiles) {
            // get everything you need from these files
            try {
                AndroidLogger.reinitAndroidLogger();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });

Aquí está el enlace a la página de github con más información: https://github.com/danylovolokh/AndroidLogger

Espero eso ayude.

Danylo Volokh
fuente
1

Muchas de las versiones anteriores en log4j no funcionan ahora (05/2019). Pero puede usar Hyperlog: puedo confirmar que funciona.

  1. Agregue esta línea a sus dependencias y proyecto de sincronización

    implementation 'com.hypertrack:hyperlog:0.0.10'
  2. Cree una nueva clase de aplicación (cree una nueva clase java y extienda la aplicación). Luego, en el método onCreate, agregue estas líneas:

    HyperLog.initialize(this);
    HyperLog.setLogLevel(Log.VERBOSE);
    
    HyperLog.getDeviceLogsInFile(this);
  3. Cambie el archivo de manifiesto para que se defina el archivo de la aplicación.

    <application
        android:name=".AppClass"
        .....
  4. Diferentes formas de iniciar sesión:

    HyperLog.d(TAG,"debug");
    HyperLog.i(TAG,"information");
    HyperLog.e(TAG,"error");
    HyperLog.v(TAG,"verbose");
    HyperLog.w(TAG,"warning");
    HyperLog.a(TAG,"assert");
    HyperLog.exception(TAG,"exception",throwable);
  5. Encuentra tus archivos de registro. Navegar a

    RootFolder/android/data/"appPackageName/LogFiles/
Haider Malik
fuente
Probé esta biblioteca, en el archivo generado con HyperLog.getDeviceLogsInFile (esto); solo el último registro generado está allí
mad_greasemonkey