简体   繁体   English

如何将STDOUT重定向到NSTextView?

[英]How to redirect STDOUT to a NSTextView?

Could anybody show me how to redirect the Stdout to a NSTextView? 有人能告诉我如何将Stdout重定向到NSTextView吗?

and whether the info print by NSLog belong to the std? 以及NSLog打印的信息是否属于std?

Thanks 谢谢

The code below uses dup2 to plug stdout onto the write-end of an NSPipe object. 下面的代码使用dup2将stdout插入NSPipe对象的写端。 The read-end is observed with a GCD dispatch source, that reads data from the pipe and appends it to a textview. 使用GCD调度源观察读取端,该源从管道读取数据并将其附加到textview。

NSPipe* pipe = [NSPipe pipe];
NSFileHandle* pipeReadHandle = [pipe fileHandleForReading];
dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout));
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, [pipeReadHandle fileDescriptor], 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
dispatch_source_set_event_handler(source, ^{
    void* data = malloc(4096);
    ssize_t readResult = 0;
    do
    {
        errno = 0;
        readResult = read([pipeReadHandle fileDescriptor], data, 4096);
    } while (readResult == -1 && errno == EINTR);
    if (readResult > 0)
    {
        //AppKit UI should only be updated from the main thread
        dispatch_async(dispatch_get_main_queue(),^{
            NSString* stdOutString = [[NSString alloc] initWithBytesNoCopy:data length:readResult encoding:NSUTF8StringEncoding freeWhenDone:YES];
            NSAttributedString* stdOutAttributedString = [[NSAttributedString alloc] initWithString:stdOutString];
            [self.logView.textStorage appendAttributedString:stdOutAttributedString];
        });
    }
    else{free(data);}
});
dispatch_resume(source);

NSLog(@"...") does not output to stdout though - It prints to stderr . NSLog(@"...")不输出到stdout - 它打印到stderr If you want to redirect that into your textview, change 如果要将其重定向到文本视图,请更改

dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stdout));

to

dup2([[pipe fileHandleForWriting] fileDescriptor], fileno(stderr));

if the goal is to handle your NSLog output only, not the system generated error logs, there is an other way to do so, here is a code to overclass NSLog. 如果目标只是处理你的NSLog输出,而不是系统生成的错误日志,还有另一种方法,这里有一个代码来覆盖NSLog。 This code is only printing the log and some extra information on stderr instead of the usual NSLog output, but you can make any changes that suites your needs inside the HyperLog function : 此代码仅打印日志和stderr的一些额外信息,而不是通常的NSLog输出,但您可以在HyperLog函数内进行任何满足您需求的更改:

HyperLog.h HyperLog.h

#import <Foundation/Foundation.h>

#ifdef HYPER_LOG
#define NSLog(args...) HyperLog(__FILE__,__LINE__,__PRETTY_FUNCTION__,args);
#else
#define NSLog(x...)
#endif

void HyperLog(const char *file, int lineNumber, const char *functionName, NSString *format, ...);

Hyperlog.m Hyperlog.m

#import "HyperLog.h"

void HyperLog(const char *file, int lineNumber, const char *functionName, NSString *format, ...)
{
    va_list ap;
    va_start (ap, format);
    if (![format hasSuffix: @"\n"])
    {
        format = [format stringByAppendingString: @"\n"];
    }

    NSString *body = [[NSString alloc] initWithFormat:format arguments:ap];
    va_end (ap);
     NSString *fileName = [[NSString stringWithUTF8String:file] lastPathComponent];
    char mesg[8192]="\0";
    NSDate *now =[NSDate date];
    NSString *dateString = [NSDateFormatter localizedStringFromDate:now dateStyle:NSDateFormatterShortStyle timeStyle:NSDateFormatterMediumStyle];
    if ( sprintf( mesg, "<%s.%03.0f> : %s\n<%s : %d - %s>\n", [dateString UTF8String],roundf(fmod( [now timeIntervalSinceReferenceDate], 1 ) * 1000), [body UTF8String], [fileName UTF8String],
                 lineNumber,
            functionName) < 0 ) printf("message creation failed\n");
    fprintf(stderr, "%s", mesg );
}

You then only need to put these 2 lines on top of any of your program file to have it work 然后,您只需将这两行放在任何程序文件的顶部即可使其工作

#define HYPER_LOG
#import "HyperLog.h"

I tried to use the above code from Thomas to have the result data of a system generated error log written to a text file using a C function, that works properly in other contexts, but it keeps and crashing, and the error reason is lost in the process. 我尝试使用Thomas的上述代码将系统生成的错误日志的结果数据使用C函数写入文本文件,该函数在其他上下文中正常工作,但它保持并崩溃,并且错误原因在这个过程。 Anyone has an idea why ? 任何人都知道为什么?

I know the question was about objective-c but I thought I would post a swift answer incase that helps someone else. 我知道这个问题是关于objective-c但是我想我会发布一个快速的答案来帮助别人。

let pipefd = UnsafeMutablePointer<Int32>.allocate(capacity: 8)
pipe(pipefd)

dup2(pipefd[1], fileno(stdout))

// Print something here

let buf = UnsafeMutableRawPointer.allocate(byteCount: 1024, alignment: 0)
read(pipefd[0], buf, 100)

close(pipefd[1])

let output = self.ptrToString(pointer: buf)
if output != "" {
    // Do something with output
}

buf.deallocate()
pipefd.deallocate()

And here is the function I use to convert the pointer to a string: 这是我用来将指针转换为字符串的函数:

func ptrToString (pointer buf: UnsafeMutableRawPointer) -> String {
    let filteredArray = Array(UnsafeBufferPointer(start: buf.assumingMemoryBound(to: UInt8.self), count: 1024)).filter { item in
        return item != 0
    }

    return filteredArray
        .map { String(UnicodeScalar(UInt8($0))) }
        .joined()
        .components(separatedBy: "\n")[0]
}

Works on swift 4 适用于swift 4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM