Android将日志写入文本文件


128

我正在尝试使用此Mine代码将日志写入Android文件上的Custom Log.txt文件,但随后此方法创建文件但不包含任何内容。基本上,我想读取文件的先前内容,然后将数据附加到现有内容之后。

代码如下:

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();
            }
        }

Answers:


247

希望这可以帮助...

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();
   }
}

82
不要忘记为清单中的Writing_external_storage添加权限!
病毒2012年

5
我需要添加buf.flush(); beforebuf.close(); 但是tjis函数正是我所需要的。谢谢
Csabi

1
我应该从哪里调用此函数,以便它在文件中写入所有应用程序的登录信息???
uniruddh 2014年

10
我建议重组代码,使其buf.close()位于一个finally块内。
威廉·普赖斯

2
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />当然,@ virusss8是什么意思。
Bengt

29

对于那些不熟悉Java常规日志记录和Android日志记录的人

  1. Log4j是通用的Java日志记录实现,现在是Apache软件基础的项目。它不是特定于Android的,因此与Android有一些不兼容。
  2. SL4J不是日志记录实现,它是抽象层。它有助于避免类似每个第三方库对项目的依赖之类的情况,从而尝试使用自己的日志记录实现(例如Log4j)。来源

以下是在Android中登录txt的一些选项

  1. 使用logcat -f在本作的答案记录到文件中。请注意,从Android 4.2开始,READ_LOGS权限不会产生任何影响,并且每个应用程序(除非植根于手机)只能读取自己的日志。这里的缺点是logcat缓冲区是循环的,并且具有大小限制。您可能没有得到较早的日志。
  2. 使用microlog4android(为Android等移动设备编写),如先前的答案所示。可能有一种方法,但我不知道如何使用microlog4Android记录到应用程序内部存储。日志路径的唯一选择是sdcard之类的外部存储,因此我无法使用它。
  3. Log4jandroid-logging-log4j结合使用。android-logging-log4j是做什么的?通过提供两个功能,它使Log4j在Android中更易于使用。

    • 除了日志文件,还可以选择将日志发送到logcat
    • 通过提供LogConfigurator类来设置Log4j配置选项(如文件路径,最大文件大小,备份数量等)的简单方法。

    下面的简单示例。请注意,logger以下示例中的对象是返回的Log4j对象,而不是android-logging-log4j类。因此android-logging-log4j仅用于配置Log4j。

  4. 尚未尝试LogBack。LogBack由提出Log4J 1.x和SL4J库的同一人开发。虽然与Log4j 2.x不相关。

在Android中使用Log4j的步骤。

  1. log4j-1.2.x.jarandroid-logging-log4j-1.0.3.jar都添加到libs文件夹中。

  2. 仅在使用外部存储时添加权限
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

  3. 编写Log4j助手类

    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. 活动课

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

来源示例。请注意,从头开始重写的log4j 2.x(改进的功能)不能与log4j 1.x向后兼容。因此,您必须将log4j 1.2.x jar与android-logging-log4j jar一起使用。我能够登录到应用程序内部文件,然后通过电子邮件将其发送给setReadable(true, false)


24

microlog4android对我有用,但文档非常差。他们需要添加的只是一个快速入门教程

这是我找到的快速教程。

  1. 在您的主活动中添加以下静态变量:

    private static final Logger logger = LoggerFactory.getLogger();
  2. 将以下内容添加到您的onCreate()方法中:

    PropertyConfigurator.getConfigurator(this).configure();
  3. 创建一个名为的文件microlog.properties并将其存储在assets目录中

  4. microlog.properties如下编辑文件:

    microlog.level=DEBUG
    microlog.appender=LogCatAppender;FileAppender
    microlog.formatter=PatternFormatter
    microlog.formatter.PatternFormatter.pattern=%c [%P] %m %T
  5. 添加这样的日志记录语句:

    logger.debug("M4A");

对于每个类,您都按照1)中的指定创建一个记录器对象

6.您可能会添加以下权限:

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

这是教程的来源


4
FileAppender将在你的SD卡创建文件“microlog.txt”(在我的情况下完整路径是“/sdcard/microlog.txt)
鲁斯兰Yanchyshyn

2
本快速教程应该是Microlog4Android官方文档的一部分。
约翰·卡尔森

错误:Android Dex:[项目] com.android.dex.DexException:多个dex文件定义了Lcom / google / code / microlog4android / Level; ?

10

警告:我可能完全误解了您,但是如果您只想要一个日志文件,为什么要出汗?

将其放在bat文件中(将路径更改为tools目录,并且yourappname当然是您的应用名称):

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"

然后在您的代码中执行类似以下操作:

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

要创建日志,请连接USB电缆并运行bat文件。

问候


不要忘记导入android.util.Log。
蜘蛛侠

它返回“错误:不止一个设备和仿真器-等待设备-”,仅此而已。有什么事吗
eros

20
如果您在运行应用程序时不在PC附近,该如何工作?
DDSports 2014年

@DDSports没有。但是他不明白问题的实质
Ewoks

@DDSports您可以通过wifi使用adb。
Daniel F

8

使用slf4android lib。
这是使用android java.util.logging。* 的slf4j api的简单实现。

特征:

  • 开箱即用地记录文件
  • 记录到任何其他目的地 LoggerConfiguration.configuration().addHandlerToLogger
  • 摇动设备以通过电子邮件发送带有屏幕截图的日志
  • 很小,只需要约55kB

slf4android主要由@miensol维护。

在我们的博客上阅读有关slf4android的更多信息:


7

您应该看看microlog4android。他们有准备登录到文件的解决方案。

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


12
这似乎是一个很好的库,但是文档太糟糕了。我根本不知道如何使它工作并最终自己组装了一些东西。
Paul Lammertsma

@PaulLammertsma:我认为您为Microlog4Android做出了贡献是一件很好的事情。仅供参考:它具有与Log4j相同的API。对不起,糟糕的文档。
约翰·卡尔森

@Paul Lammertsma如果文档中有这么糟糕的内容,您不能使用它,那怎么会是一件好事呢?如果您无法使它正常工作,那就太糟糕了。
令人难以置信的

7

这可能已经晚了,但希望对您有所帮助。

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();
            }
        }

这里bfwritter.newline将您的文本写入文件。并添加权限

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

在清单文件中,不会失败。


6

我通过以下命令行方式解决了此问题:

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

其中的“时间”选项添加了日期,调用时间,优先级/标签和发出消息的进程的PID的元数据字段详细信息。

然后在您的代码中执行与此类似的操作(使用android.util.Log):

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

4
adb连接时可以很好地工作,但是当设备处于独立模式时则不能工作。我不会在生产中使用它,但是它是调试模式下的简单解决方案。
朱利安·克朗格

2

通常,在打开流之前,您必须具有文件句柄。在else块中的createNewFile()之前,您具有fileOutputStream句柄。如果该流不存在,则它不会创建该文件。

并不是真正针对Android的,但这是很多IO。如果您接连进行许多“写”操作怎么办?您将阅读全部内容并编写全部内容,这需要花费时间,更重要的是,还需要电池寿命。

我建议使用java.io.RandomAccessFile,在末尾执行seek(),然后添加writeChars()。这将是更简洁的代码,并且可能更快。


2

我创建了一个简单的,轻量级的类(大约260个LoC),该类通过基于文件的日志记录扩展了标准的android.util.Log实现:
每个日志消息均通过android.util.Log进行记录,并且还写入了设备上的文本文件中。

您可以在github上找到它:https :
//github.com/volkerv/FileLog


1
难道我们需要确保在UI线程上未完成文件操作。如果我们有大量的文件记录?
Jayshil Dave 2015年

2

经过长时间的调查,我发现:

  • android.util.Log 默认使用 java.util.logging.Logger
  • LogCat logger与name ""一起使用,以获取使用它的实例LogManager.getLogManager().getLogger("")
  • Android设备在运行调试应用程序后将其添加到LogCat logger实例com.android.internal.logging.AndroidHandler
  • 但!!!com.android.internal.logging.AndroidHandler仅将级别大于java.util.logging.Level.INFOLevel.INFO, Level.WARNING, Level.SEVERE, Level.OFF)的 消息输出到logcat

因此,将日志写入文件只需rootLogger "" 添加一个即可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
        }
    }
}

要在您的应用程序中打印所有记录器,请使用:

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()
    }

你好 使用此“”记录器有什么好处。我认为自定义记录器没有什么区别。还是我想念什么?
Abins Shaji

1

这个变体要短得多

尝试{
    最终文件路径=新文件(
            Environment.getExternalStorageDirectory(),“ DBO_logs5”);
    如果(!path.exists()){
        path.mkdir();
    }
    Runtime.getRuntime()。exec(
            “ logcat -d -f” +路径+ File.separator
                    +“ dbo_logcat”
                    +“ .txt”);
} catch(IOException e){
    e.printStackTrace();
}

1

您可以使用我编写的库。它很容易使用:

将此依赖项添加到您的gradle文件中:

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

在Application类中初始化库:

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
    }

这是使用库的方式:

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

这是如何检索日志:

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();
            }
        }
    });

这是带有更多信息的github页面的链接:https : //github.com/danylovolokh/AndroidLogger

希望能帮助到你。


1

log4j上的许多先前版本现在不起作用(05/2019)。但是您可以使用Hyperlog-我可以确认它是否有效。

  1. 将此行添加到您的依赖项和同步项目中

    implementation 'com.hypertrack:hyperlog:0.0.10'
  2. 创建一个新的应用程序类(创建一个新的Java类并扩展Application)。然后在onCreate方法中添加以下行:

    HyperLog.initialize(this);
    HyperLog.setLogLevel(Log.VERBOSE);
    
    HyperLog.getDeviceLogsInFile(this);
  3. 更改清单文件以定义应用程序文件。

    <application
        android:name=".AppClass"
        .....
  4. 不同的日志记录方式:

    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. 查找您的日志文件。导航

    RootFolder/android/data/"appPackageName/LogFiles/

我在通过HyperLog.getDeviceLogsInFile(this)生成的文件中尝试了该库。只有最后生成的日志在这里
mad_greasemonkey
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.